1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktext_p.h"
43 #include "qquicktext_p_p.h"
45 #include <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>
60 #include <private/qdeclarativestyledtext_p.h>
61 #include <QtQuick/private/qdeclarativepixmapcache_p.h>
68 extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
70 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
71 DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE);
73 QString QQuickTextPrivate::elideChar = QString(0x2026);
75 QQuickTextPrivate::QQuickTextPrivate()
76 : color((QRgb)0), style(QQuickText::Normal), hAlign(QQuickText::AlignLeft),
77 vAlign(QQuickText::AlignTop), elideMode(QQuickText::ElideNone),
78 format(QQuickText::AutoText), wrapMode(QQuickText::NoWrap), lineHeight(1),
79 lineHeightMode(QQuickText::ProportionalHeight), lineCount(1), maximumLineCount(INT_MAX),
80 maximumLineCountValid(false),
82 imageCacheDirty(false), updateOnComponentComplete(true),
83 richText(false), styledText(false), singleline(false), cacheAllTextAsImage(true), internalWidthUpdate(false),
84 requireImplicitWidth(false), truncated(false), hAlignImplicit(true), rightToLeftText(false),
85 layoutTextElided(false), richTextAsImage(false), textureImageCacheDirty(false), textHasChanged(true),
86 naturalWidth(0), doc(0), elipsisLayout(0), textLine(0), nodeType(NodeIsNull)
89 , layoutThread(0), paintingThread(0)
93 cacheAllTextAsImage = enableImageCache();
96 void QQuickTextPrivate::init()
99 q->setAcceptedMouseButtons(Qt::LeftButton);
100 q->setFlag(QQuickItem::ItemHasContents);
103 QQuickTextDocumentWithImageResources::QQuickTextDocumentWithImageResources(QQuickItem *parent)
104 : QTextDocument(parent), outstanding(0)
106 setUndoRedoEnabled(false);
109 QQuickTextDocumentWithImageResources::~QQuickTextDocumentWithImageResources()
111 if (!m_resources.isEmpty())
112 qDeleteAll(m_resources);
115 QVariant QQuickTextDocumentWithImageResources::loadResource(int type, const QUrl &name)
117 QDeclarativeContext *context = qmlContext(parent());
118 QUrl url = context->resolvedUrl(name);
120 if (type == QTextDocument::ImageResource) {
121 QHash<QUrl, QDeclarativePixmap *>::Iterator iter = m_resources.find(url);
123 if (iter == m_resources.end()) {
124 QDeclarativePixmap *p = new QDeclarativePixmap(context->engine(), url);
125 iter = m_resources.insert(url, p);
127 if (p->isLoading()) {
128 p->connectFinished(this, SLOT(requestFinished()));
133 QDeclarativePixmap *p = *iter;
136 } else if (p->isError()) {
137 if (!errors.contains(url)) {
139 qmlInfo(parent()) << p->error();
144 return QTextDocument::loadResource(type,url); // The *resolved* URL
147 void QQuickTextDocumentWithImageResources::requestFinished()
150 if (outstanding == 0) {
151 markContentsDirty(0, characterCount());
153 if (QQuickText *item = qobject_cast<QQuickText *>(parent()))
154 QQuickTextPrivate::get(item)->updateLayout();
158 void QQuickTextDocumentWithImageResources::clear()
162 QTextDocument::clear();
165 void QQuickTextDocumentWithImageResources::clearResources()
167 foreach (QDeclarativePixmap *pixmap, m_resources)
169 qDeleteAll(m_resources);
174 void QQuickTextDocumentWithImageResources::setText(const QString &text)
178 #ifndef QT_NO_TEXTHTMLPARSER
185 QSet<QUrl> QQuickTextDocumentWithImageResources::errors;
187 QQuickTextPrivate::~QQuickTextPrivate()
189 delete elipsisLayout;
190 delete textLine; textLine = 0;
193 qreal QQuickTextPrivate::getImplicitWidth() const
195 if (!requireImplicitWidth) {
196 // We don't calculate implicitWidth unless it is required.
197 // We need to force a size update now to ensure implicitWidth is calculated
198 QQuickTextPrivate *me = const_cast<QQuickTextPrivate*>(this);
199 me->requireImplicitWidth = true;
202 return implicitWidth;
205 void QQuickTextPrivate::updateLayout()
208 if (!q->isComponentComplete()) {
209 updateOnComponentComplete = true;
212 updateOnComponentComplete = false;
213 layoutTextElided = false;
214 // Setup instance of QTextLayout for all cases other than richtext
217 delete elipsisLayout;
220 layout.clearLayout();
221 layout.setFont(font);
224 tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
225 singleline = !tmp.contains(QChar::LineSeparator);
226 if (singleline && !maximumLineCountValid && elideMode != QQuickText::ElideNone && q->widthValid() && wrapMode == QQuickText::NoWrap) {
227 if (q->width() <= 0) {
230 QFontMetrics fm(font);
231 tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width());
234 layoutTextElided = true;
237 emit q->truncatedChanged();
244 if (textHasChanged) {
245 QDeclarativeStyledText::parse(text, layout);
246 textHasChanged = false;
251 QTextBlockFormat::LineHeightTypes type;
252 type = lineHeightMode == QQuickText::FixedHeight ? QTextBlockFormat::FixedHeight : QTextBlockFormat::ProportionalHeight;
253 QTextBlockFormat blockFormat;
254 blockFormat.setLineHeight((lineHeightMode == QQuickText::FixedHeight ? lineHeight : lineHeight * 100), type);
255 for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next()) {
256 QTextCursor cursor(it);
257 cursor.mergeBlockFormat(blockFormat);
264 void QQuickTextPrivate::updateSize()
268 if (!q->isComponentComplete()) {
269 updateOnComponentComplete = true;
273 if (!requireImplicitWidth) {
274 emit q->implicitWidthChanged();
275 // if the implicitWidth is used, then updateSize() has already been called (recursively)
276 if (requireImplicitWidth)
280 invalidateImageCache();
282 QFontMetrics fm(font);
283 if (text.isEmpty()) {
284 q->setImplicitSize(0, fm.height());
285 paintedSize = QSize(0, fm.height());
286 emit q->paintedSizeChanged();
291 int dy = q->height();
294 #if defined(Q_OS_MAC)
295 layoutThread = QThread::currentThread();
298 //setup instance of QTextLayout for all cases other than richtext
300 QRect textRect = setupTextLayout();
301 layedOutTextRect = textRect;
302 size = textRect.size();
305 singleline = false; // richtext can't elide or be optimized for single-line case
307 doc->setDefaultFont(font);
308 QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign();
309 if (rightToLeftText) {
310 if (horizontalAlignment == QQuickText::AlignLeft)
311 horizontalAlignment = QQuickText::AlignRight;
312 else if (horizontalAlignment == QQuickText::AlignRight)
313 horizontalAlignment = QQuickText::AlignLeft;
316 option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
317 option.setWrapMode(QTextOption::WrapMode(wrapMode));
318 if (!cacheAllTextAsImage && !richTextAsImage && !qmlDisableDistanceField())
319 option.setUseDesignMetrics(true);
320 doc->setDefaultTextOption(option);
321 if (requireImplicitWidth && q->widthValid()) {
322 doc->setTextWidth(-1);
323 naturalWidth = doc->idealWidth();
325 if (wrapMode != QQuickText::NoWrap && q->widthValid())
326 doc->setTextWidth(q->width());
328 doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
329 dy -= (int)doc->size().height();
330 QSize dsize = doc->size().toSize();
331 layedOutTextRect = QRect(QPoint(0,0), dsize);
332 size = QSize(int(doc->idealWidth()),dsize.height());
336 if (q->heightValid()) {
337 if (vAlign == QQuickText::AlignBottom)
339 else if (vAlign == QQuickText::AlignVCenter)
342 q->setBaselineOffset(fm.ascent() + yoff);
344 //### need to comfirm cost of always setting these for richText
345 internalWidthUpdate = true;
347 if (!q->widthValid())
348 iWidth = size.width();
349 else if (requireImplicitWidth)
350 iWidth = naturalWidth;
352 q->setImplicitSize(iWidth, size.height());
353 internalWidthUpdate = false;
356 q->setImplicitHeight(size.height());
357 if (paintedSize != size) {
359 emit q->paintedSizeChanged();
364 QQuickTextLine::QQuickTextLine()
365 : QObject(), m_line(0), m_height(0)
369 void QQuickTextLine::setLine(QTextLine *line)
374 int QQuickTextLine::number() const
377 return m_line->lineNumber();
381 qreal QQuickTextLine::width() const
384 return m_line->width();
388 void QQuickTextLine::setWidth(qreal width)
391 m_line->setLineWidth(width);
394 qreal QQuickTextLine::height() const
399 return m_line->height();
403 void QQuickTextLine::setHeight(qreal height)
406 m_line->setPosition(QPointF(m_line->x(), m_line->y() - m_line->height() + height));
410 qreal QQuickTextLine::x() const
417 void QQuickTextLine::setX(qreal x)
420 m_line->setPosition(QPointF(x, m_line->y()));
423 qreal QQuickTextLine::y() const
430 void QQuickTextLine::setY(qreal y)
433 m_line->setPosition(QPointF(m_line->x(), y));
436 void QQuickText::doLayout()
442 bool QQuickTextPrivate::isLineLaidOutConnected()
444 static int idx = this->signalIndex("lineLaidOut(QQuickTextLine*)");
445 return this->isSignalConnected(idx);
448 void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, qreal elideWidth = 0)
452 #if defined(Q_OS_MAC)
453 if (QThread::currentThread() != paintingThread) {
455 if (!line.lineNumber())
459 textLine = new QQuickTextLine;
460 textLine->setLine(&line);
461 textLine->setY(height);
462 textLine->setHeight(0);
464 // use the text item's width by default if it has one and wrap is on
465 if (q->widthValid() && q->wrapMode() != QQuickText::NoWrap)
466 textLine->setWidth(q->width() - elideWidth);
468 textLine->setWidth(INT_MAX);
469 if (lineHeight != 1.0)
470 textLine->setHeight((lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight);
472 emit q->lineLaidOut(textLine);
474 linesRects << QRectF(textLine->x(), textLine->y(), textLine->width(), textLine->height());
475 height += textLine->height();
477 #if defined(Q_OS_MAC)
479 if (line.lineNumber() < linesRects.count()) {
480 QRectF r = linesRects.at(line.lineNumber());
481 line.setLineWidth(r.width());
482 line.setPosition(r.topLeft());
489 Lays out the QQuickTextPrivate::layout QTextLayout in the constraints of the QQuickText.
491 Returns the size of the final text. This can be used to position the text vertically (the text is
492 already absolutely positioned horizontally).
494 QRect QQuickTextPrivate::setupTextLayout()
496 // ### text layout handling should be profiled and optimized as needed
497 // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
499 layout.setCacheEnabled(true);
502 int visibleCount = 0;
506 lineWidth = q->width();
508 QTextOption textOption = layout.textOption();
509 textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
510 textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
511 if (!cacheAllTextAsImage && !richTextAsImage && !qmlDisableDistanceField())
512 textOption.setUseDesignMetrics(true);
513 layout.setTextOption(textOption);
515 QFontMetrics fm(layout.font());
516 elidePos = QPointF();
518 if (requireImplicitWidth && q->widthValid()) {
519 // requires an extra layout
521 if (layoutTextElided) {
522 // We have provided elided text to the layout, but we must calculate unelided width.
523 elidedText = layout.text();
524 layout.setText(text);
526 layout.beginLayout();
528 QTextLine line = layout.createLine();
534 for (int i = 0; i < layout.lineCount(); ++i) {
535 QTextLine line = layout.lineAt(i);
536 br = br.united(line.naturalTextRect());
538 naturalWidth = br.width();
539 if (layoutTextElided)
540 layout.setText(elidedText);
543 if ((q->widthValid() && q->width() <= 0. && elideMode != QQuickText::ElideNone)
544 || (q->heightValid() && q->height() <= 0. && wrapMode != QQuickText::NoWrap && elideMode == QQuickText::ElideRight)) {
545 // we are elided and we have a zero width or height
548 emit q->truncatedChanged();
552 emit q->lineCountChanged();
555 qreal height = (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : fm.height() * lineHeight;
556 return QRect(0, 0, 0, height);
562 bool truncate = layoutTextElided;
563 bool customLayout = isLineLaidOutConnected();
564 bool elideEnabled = elideMode == QQuickText::ElideRight && q->widthValid();
566 layout.beginLayout();
569 int linesLeft = maximumLineCount;
570 int visibleTextLength = 0;
572 QTextLine line = layout.createLine();
578 qreal preLayoutHeight = height;
580 setupCustomLineGeometry(line, height);
581 } else if (lineWidth) {
582 line.setLineWidth(lineWidth);
583 line.setPosition(QPointF(line.position().x(), height));
584 height += (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight;
588 if (elideEnabled && q->heightValid() && height > q->height()) {
589 // This line does not fit in the remaining area.
591 if (visibleCount > 1) {
593 height = preLayoutHeight;
594 line.setLineWidth(0.0);
595 line.setPosition(QPointF(FLT_MAX,FLT_MAX));
596 line = layout.lineAt(visibleCount-1);
599 visibleTextLength += line.textLength();
602 if (elide || (maximumLineCountValid && --linesLeft == 0)) {
603 if (visibleTextLength < text.length()) {
606 qreal elideWidth = fm.width(elideChar);
607 // Need to correct for alignment
609 setupCustomLineGeometry(line, height, elideWidth);
611 line.setLineWidth(lineWidth - elideWidth);
612 if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) {
613 line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y()));
614 elidePos.setX(line.naturalTextRect().left() - elideWidth);
616 elidePos.setX(line.naturalTextRect().right());
618 elidePos.setY(line.position().y());
620 elipsisLayout = new QTextLayout(elideChar, layout.font());
621 elipsisLayout->beginLayout();
622 QTextLine el = elipsisLayout->createLine();
623 el.setPosition(elidePos);
624 elipsisLayout->endLayout();
625 br = br.united(el.naturalTextRect());
627 br = br.united(line.naturalTextRect());
631 br = br.united(line.naturalTextRect());
636 if (truncated != truncate) {
637 truncated = truncate;
638 emit q->truncatedChanged();
642 br.setHeight(height);
644 if (!q->widthValid())
645 naturalWidth = br.width();
647 //Update the number of visible lines
648 if (lineCount != visibleCount) {
649 lineCount = visibleCount;
650 emit q->lineCountChanged();
653 return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height()));
657 Returns a painted version of the QQuickTextPrivate::layout QTextLayout.
658 If \a drawStyle is true, the style color overrides all colors in the document.
660 QPixmap QQuickTextPrivate::textLayoutImage(bool drawStyle)
662 QSize size = layedOutTextRect.size();
666 if (!size.isEmpty()) {
667 img.fill(Qt::transparent);
668 /*#ifdef Q_OS_MAC // Fails on CocoaX64
669 bool oldSmooth = qt_applefontsmoothing_enabled;
670 qt_applefontsmoothing_enabled = false;
673 /*#ifdef Q_OS_MAC // Fails on CocoaX64
674 qt_applefontsmoothing_enabled = oldSmooth;
676 drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle);
682 Paints the QQuickTextPrivate::layout QTextLayout into \a painter at \a pos. If
683 \a drawStyle is true, the style color overrides all colors in the document.
685 void QQuickTextPrivate::drawTextLayout(QPainter *painter, const QPointF &pos, bool drawStyle)
688 painter->setPen(styleColor);
690 painter->setPen(color);
691 painter->setFont(font);
692 layout.draw(painter, pos);
693 if (!elidePos.isNull())
694 painter->drawText(pos + elidePos, elideChar);
698 Returns a painted version of the QQuickTextPrivate::doc QTextDocument.
699 If \a drawStyle is true, the style color overrides all colors in the document.
701 QPixmap QQuickTextPrivate::textDocumentImage(bool drawStyle)
703 QSize size = doc->size().toSize();
707 img.fill(Qt::transparent);
708 /*#ifdef Q_OS_MAC // Fails on CocoaX64
709 bool oldSmooth = qt_applefontsmoothing_enabled;
710 qt_applefontsmoothing_enabled = false;
713 /*#ifdef Q_OS_MAC // Fails on CocoaX64
714 qt_applefontsmoothing_enabled = oldSmooth;
717 QAbstractTextDocumentLayout::PaintContext context;
719 QTextOption oldOption(doc->defaultTextOption());
721 context.palette.setColor(QPalette::Text, styleColor);
722 QTextOption colorOption(doc->defaultTextOption());
723 colorOption.setFlags(QTextOption::SuppressColors);
724 doc->setDefaultTextOption(colorOption);
726 context.palette.setColor(QPalette::Text, color);
728 doc->documentLayout()->draw(&p, context);
730 doc->setDefaultTextOption(oldOption);
735 Mark the image cache as dirty.
737 void QQuickTextPrivate::invalidateImageCache()
741 if (richTextAsImage || cacheAllTextAsImage || (qmlDisableDistanceField() && style != QQuickText::Normal)) { // If actually using the image cache
745 imageCacheDirty = true;
747 if (q->isComponentComplete())
748 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
749 } else if (q->isComponentComplete())
754 Tests if the image cache is dirty, and repaints it if it is.
756 void QQuickTextPrivate::checkImageCache()
760 if (!imageCacheDirty)
763 if (text.isEmpty()) {
765 imageCache = QPixmap();
773 textImage = textDocumentImage(false);
774 if (style != QQuickText::Normal)
775 styledImage = textDocumentImage(true); //### should use styleColor
777 textImage = textLayoutImage(false);
778 if (style != QQuickText::Normal)
779 styledImage = textLayoutImage(true); //### should use styleColor
783 case QQuickText::Outline:
784 imageCache = drawOutline(textImage, styledImage);
786 case QQuickText::Sunken:
787 imageCache = drawOutline(textImage, styledImage, -1);
789 case QQuickText::Raised:
790 imageCache = drawOutline(textImage, styledImage, 1);
793 imageCache = textImage;
799 imageCacheDirty = false;
800 textureImageCacheDirty = true;
805 Ensures the QQuickTextPrivate::doc variable is set to a valid text document
807 void QQuickTextPrivate::ensureDoc()
811 doc = new QQuickTextDocumentWithImageResources(q);
812 doc->setDocumentMargin(0);
817 Draw \a styleSource as an outline around \a source and return the new image.
819 QPixmap QQuickTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource)
821 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
822 img.fill(Qt::transparent);
827 pos += QPoint(-1, 0);
828 ppm.drawPixmap(pos, styleSource);
830 ppm.drawPixmap(pos, styleSource);
831 pos += QPoint(-1, -1);
832 ppm.drawPixmap(pos, styleSource);
834 ppm.drawPixmap(pos, styleSource);
836 pos += QPoint(0, -1);
837 ppm.drawPixmap(pos, source);
844 Draw \a styleSource below \a source at \a yOffset and return the new image.
846 QPixmap QQuickTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset)
848 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
849 img.fill(Qt::transparent);
853 ppm.drawPixmap(QPoint(0, yOffset), styleSource);
854 ppm.drawPixmap(0, 0, source);
862 \qmlclass Text QQuickText
863 \inqmlmodule QtQuick 2
864 \ingroup qml-basic-visual-elements
865 \brief The Text item allows you to add formatted text to a scene.
868 Text items can display both plain and rich text. For example, red text with
869 a specific font and size can be defined like this:
874 font.family: "Helvetica"
880 Rich text is defined using HTML-style markup:
884 text: "<b>Hello</b> <i>World!</i>"
888 \image declarative-text.png
890 If height and width are not explicitly set, Text will attempt to determine how
891 much room is needed and set it accordingly. Unless \l wrapMode is set, it will always
892 prefer width to height (all text will be placed on a single line).
894 The \l elide property can alternatively be used to fit a single line of
895 plain text to a set width.
897 Note that the \l{Supported HTML Subset} is limited. Also, if the text contains
898 HTML img tags that load remote images, the text is reloaded.
900 Text provides read-only text. For editable text, see \l TextEdit.
902 \sa {declarative/text/fonts}{Fonts example}
904 QQuickText::QQuickText(QQuickItem *parent)
905 : QQuickImplicitSizeItem(*(new QQuickTextPrivate), parent)
911 QQuickText::~QQuickText()
916 \qmlproperty bool QtQuick2::Text::clip
917 This property holds whether the text is clipped.
919 Note that if the text does not fit in the bounding rectangle it will be abruptly chopped.
921 If you want to display potentially long text in a limited space, you probably want to use \c elide instead.
925 \qmlproperty bool QtQuick2::Text::smooth
927 This property holds whether the text is smoothly scaled or transformed.
929 Smooth filtering gives better visual quality, but is slower. If
930 the item is displayed at its natural size, this property has no visual or
933 \note Generally scaling artifacts are only visible if the item is stationary on
934 the screen. A common pattern when animating an item is to disable smooth
935 filtering at the beginning of the animation and reenable it at the conclusion.
939 \qmlsignal QtQuick2::Text::onLineLaidOut(line)
941 This handler is called for every line during the layout process.
942 This gives the opportunity to position and resize a line as it is being laid out.
943 It can for example be used to create columns or lay out text around objects.
945 The properties of a line are:
947 \o number (read-only)
954 For example, this will move the first 5 lines of a text element by 100 pixels to the right:
957 if (line.number < 5) {
958 line.x = line.x + 100
959 line.width = line.width - 100
966 \qmlsignal QtQuick2::Text::onLinkActivated(string link)
968 This handler is called when the user clicks on a link embedded in the text.
969 The link must be in rich text or HTML format and the
970 \a link string provides access to the particular link.
972 \snippet doc/src/snippets/declarative/text/onLinkActivated.qml 0
974 The example code will display the text
975 "The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}."
977 Clicking on the highlighted link will output
978 \tt{http://qt.nokia.com link activated} to the console.
982 \qmlproperty string QtQuick2::Text::font.family
984 Sets the family name of the font.
986 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
987 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
988 If the family isn't available a family will be set using the font matching algorithm.
992 \qmlproperty bool QtQuick2::Text::font.bold
994 Sets whether the font weight is bold.
998 \qmlproperty enumeration QtQuick2::Text::font.weight
1000 Sets the font's weight.
1002 The weight can be one of:
1005 \o Font.Normal - the default
1012 Text { text: "Hello"; font.weight: Font.DemiBold }
1017 \qmlproperty bool QtQuick2::Text::font.italic
1019 Sets whether the font has an italic style.
1023 \qmlproperty bool QtQuick2::Text::font.underline
1025 Sets whether the text is underlined.
1029 \qmlproperty bool QtQuick2::Text::font.strikeout
1031 Sets whether the font has a strikeout style.
1035 \qmlproperty real QtQuick2::Text::font.pointSize
1037 Sets the font size in points. The point size must be greater than zero.
1041 \qmlproperty int QtQuick2::Text::font.pixelSize
1043 Sets the font size in pixels.
1045 Using this function makes the font device dependent.
1046 Use \c pointSize to set the size of the font in a device independent manner.
1050 \qmlproperty real QtQuick2::Text::font.letterSpacing
1052 Sets the letter spacing for the font.
1054 Letter spacing changes the default spacing between individual letters in the font.
1055 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
1059 \qmlproperty real QtQuick2::Text::font.wordSpacing
1061 Sets the word spacing for the font.
1063 Word spacing changes the default spacing between individual words.
1064 A positive value increases the word spacing by a corresponding amount of pixels,
1065 while a negative value decreases the inter-word spacing accordingly.
1069 \qmlproperty enumeration QtQuick2::Text::font.capitalization
1071 Sets the capitalization for the text.
1074 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
1075 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
1076 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
1077 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
1078 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
1082 Text { text: "Hello"; font.capitalization: Font.AllLowercase }
1085 QFont QQuickText::font() const
1087 Q_D(const QQuickText);
1088 return d->sourceFont;
1091 void QQuickText::setFont(const QFont &font)
1094 if (d->sourceFont == font)
1097 d->sourceFont = font;
1098 QFont oldFont = d->font;
1101 if (d->font.pointSizeF() != -1) {
1103 qreal size = qRound(d->font.pointSizeF()*2.0);
1104 d->font.setPointSizeF(size/2.0);
1107 if (oldFont != d->font)
1110 emit fontChanged(d->sourceFont);
1114 \qmlproperty string QtQuick2::Text::text
1116 The text to display. Text supports both plain and rich text strings.
1118 The item will try to automatically determine whether the text should
1119 be treated as styled text. This determination is made using Qt::mightBeRichText().
1121 QString QQuickText::text() const
1123 Q_D(const QQuickText);
1127 void QQuickText::setText(const QString &n)
1133 d->richText = d->format == RichText;
1134 d->styledText = d->format == StyledText || (d->format == AutoText && Qt::mightBeRichText(n));
1136 if (isComponentComplete()) {
1140 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1141 d->richTextAsImage = enableImageCache();
1143 d->rightToLeftText = d->text.isRightToLeft();
1145 d->determineHorizontalAlignment();
1147 d->textHasChanged = true;
1149 emit textChanged(d->text);
1153 \qmlproperty color QtQuick2::Text::color
1157 An example of green text defined using hexadecimal notation:
1165 An example of steel blue text defined using an SVG color name:
1173 QColor QQuickText::color() const
1175 Q_D(const QQuickText);
1179 void QQuickText::setColor(const QColor &color)
1182 if (d->color == color)
1186 d->invalidateImageCache();
1187 emit colorChanged(d->color);
1190 \qmlproperty enumeration QtQuick2::Text::style
1192 Set an additional text style.
1194 Supported text styles are:
1196 \o Text.Normal - the default
1204 Text { font.pointSize: 24; text: "Normal" }
1205 Text { font.pointSize: 24; text: "Raised"; style: Text.Raised; styleColor: "#AAAAAA" }
1206 Text { font.pointSize: 24; text: "Outline";style: Text.Outline; styleColor: "red" }
1207 Text { font.pointSize: 24; text: "Sunken"; style: Text.Sunken; styleColor: "#AAAAAA" }
1211 \image declarative-textstyle.png
1213 QQuickText::TextStyle QQuickText::style() const
1215 Q_D(const QQuickText);
1219 void QQuickText::setStyle(QQuickText::TextStyle style)
1222 if (d->style == style)
1225 // changing to/from Normal requires the boundingRect() to change
1226 if (isComponentComplete() && (d->style == Normal || style == Normal))
1229 d->invalidateImageCache();
1230 emit styleChanged(d->style);
1234 \qmlproperty color QtQuick2::Text::styleColor
1236 Defines the secondary color used by text styles.
1238 \c styleColor is used as the outline color for outlined text, and as the
1239 shadow color for raised or sunken text. If no style has been set, it is not
1243 Text { font.pointSize: 18; text: "hello"; style: Text.Raised; styleColor: "gray" }
1248 QColor QQuickText::styleColor() const
1250 Q_D(const QQuickText);
1251 return d->styleColor;
1254 void QQuickText::setStyleColor(const QColor &color)
1257 if (d->styleColor == color)
1260 d->styleColor = color;
1261 d->invalidateImageCache();
1262 emit styleColorChanged(d->styleColor);
1266 \qmlproperty enumeration QtQuick2::Text::horizontalAlignment
1267 \qmlproperty enumeration QtQuick2::Text::verticalAlignment
1268 \qmlproperty enumeration QtQuick2::Text::effectiveHorizontalAlignment
1270 Sets the horizontal and vertical alignment of the text within the Text items
1271 width and height. By default, the text is vertically aligned to the top. Horizontal
1272 alignment follows the natural alignment of the text, for example text that is read
1273 from left to right will be aligned to the left.
1275 The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and
1276 \c Text.AlignJustify. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom
1277 and \c Text.AlignVCenter.
1279 Note that for a single line of text, the size of the text is the area of the text. In this common case,
1280 all alignments are equivalent. If you want the text to be, say, centered in its parent, then you will
1281 need to either modify the Item::anchors, or set horizontalAlignment to Text.AlignHCenter and bind the width to
1284 When using the attached property LayoutMirroring::enabled to mirror application
1285 layouts, the horizontal alignment of text will also be mirrored. However, the property
1286 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
1287 of Text, use the read-only property \c effectiveHorizontalAlignment.
1289 QQuickText::HAlignment QQuickText::hAlign() const
1291 Q_D(const QQuickText);
1295 void QQuickText::setHAlign(HAlignment align)
1298 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
1299 d->hAlignImplicit = false;
1300 if (d->setHAlign(align, forceAlign) && isComponentComplete())
1304 void QQuickText::resetHAlign()
1307 d->hAlignImplicit = true;
1308 if (isComponentComplete() && d->determineHorizontalAlignment())
1312 QQuickText::HAlignment QQuickText::effectiveHAlign() const
1314 Q_D(const QQuickText);
1315 QQuickText::HAlignment effectiveAlignment = d->hAlign;
1316 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
1317 switch (d->hAlign) {
1318 case QQuickText::AlignLeft:
1319 effectiveAlignment = QQuickText::AlignRight;
1321 case QQuickText::AlignRight:
1322 effectiveAlignment = QQuickText::AlignLeft;
1328 return effectiveAlignment;
1331 bool QQuickTextPrivate::setHAlign(QQuickText::HAlignment alignment, bool forceAlign)
1334 if (hAlign != alignment || forceAlign) {
1335 QQuickText::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
1338 emit q->horizontalAlignmentChanged(hAlign);
1339 if (oldEffectiveHAlign != q->effectiveHAlign())
1340 emit q->effectiveHorizontalAlignmentChanged();
1346 bool QQuickTextPrivate::determineHorizontalAlignment()
1348 if (hAlignImplicit) {
1349 bool alignToRight = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
1350 return setHAlign(alignToRight ? QQuickText::AlignRight : QQuickText::AlignLeft);
1355 void QQuickTextPrivate::mirrorChange()
1358 if (q->isComponentComplete()) {
1359 if (!hAlignImplicit && (hAlign == QQuickText::AlignRight || hAlign == QQuickText::AlignLeft)) {
1361 emit q->effectiveHorizontalAlignmentChanged();
1366 QTextDocument *QQuickTextPrivate::textDocument()
1371 QQuickText::VAlignment QQuickText::vAlign() const
1373 Q_D(const QQuickText);
1377 void QQuickText::setVAlign(VAlignment align)
1380 if (d->vAlign == align)
1384 emit verticalAlignmentChanged(align);
1388 \qmlproperty enumeration QtQuick2::Text::wrapMode
1390 Set this property to wrap the text to the Text item's width. The text will only
1391 wrap if an explicit width has been set. wrapMode can be one of:
1394 \o Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l paintedWidth will exceed a set width.
1395 \o Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l paintedWidth will exceed a set width.
1396 \o Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
1397 \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.
1400 QQuickText::WrapMode QQuickText::wrapMode() const
1402 Q_D(const QQuickText);
1406 void QQuickText::setWrapMode(WrapMode mode)
1409 if (mode == d->wrapMode)
1415 emit wrapModeChanged();
1419 \qmlproperty int QtQuick2::Text::lineCount
1421 Returns the number of lines visible in the text item.
1423 This property is not supported for rich text.
1425 \sa maximumLineCount
1427 int QQuickText::lineCount() const
1429 Q_D(const QQuickText);
1430 return d->lineCount;
1434 \qmlproperty bool QtQuick2::Text::truncated
1436 Returns true if the text has been truncated due to \l maximumLineCount
1439 This property is not supported for rich text.
1441 \sa maximumLineCount, elide
1443 bool QQuickText::truncated() const
1445 Q_D(const QQuickText);
1446 return d->truncated;
1450 \qmlproperty int QtQuick2::Text::maximumLineCount
1452 Set this property to limit the number of lines that the text item will show.
1453 If elide is set to Text.ElideRight, the text will be elided appropriately.
1454 By default, this is the value of the largest possible integer.
1456 This property is not supported for rich text.
1458 \sa lineCount, elide
1460 int QQuickText::maximumLineCount() const
1462 Q_D(const QQuickText);
1463 return d->maximumLineCount;
1466 void QQuickText::setMaximumLineCount(int lines)
1470 d->maximumLineCountValid = lines==INT_MAX ? false : true;
1471 if (d->maximumLineCount != lines) {
1472 d->maximumLineCount = lines;
1474 emit maximumLineCountChanged();
1478 void QQuickText::resetMaximumLineCount()
1481 setMaximumLineCount(INT_MAX);
1482 d->elidePos = QPointF();
1483 if (d->truncated != false) {
1484 d->truncated = false;
1485 emit truncatedChanged();
1490 \qmlproperty enumeration QtQuick2::Text::textFormat
1492 The way the text property should be displayed.
1494 Supported text formats are:
1497 \o Text.AutoText (default)
1503 If the text format is \c Text.AutoText the text element
1504 will automatically determine whether the text should be treated as
1505 styled text. This determination is made using Qt::mightBeRichText().
1507 Text.StyledText is an optimized format supporting some basic text
1508 styling markup, in the style of html 3.2:
1515 <u> - underlined text
1516 <font color="color_name" size="1-7"></font>
1517 <h1> to <h6> - headers
1518 <a href=""> - anchor
1519 <ol type="">, <ul type=""> and <li> - ordered and unordered lists
1523 \c Text.StyledText parser is strict, requiring tags to be correctly nested.
1532 text: "<b>Hello</b> <i>World!</i>"
1536 textFormat: Text.RichText
1537 text: "<b>Hello</b> <i>World!</i>"
1541 textFormat: Text.PlainText
1542 text: "<b>Hello</b> <i>World!</i>"
1546 \o \image declarative-textformat.png
1549 QQuickText::TextFormat QQuickText::textFormat() const
1551 Q_D(const QQuickText);
1555 void QQuickText::setTextFormat(TextFormat format)
1558 if (format == d->format)
1561 bool wasRich = d->richText;
1562 d->richText = format == RichText;
1563 d->styledText = format == StyledText || (format == AutoText && Qt::mightBeRichText(d->text));
1565 if (isComponentComplete()) {
1566 if (!wasRich && d->richText) {
1568 d->doc->setText(d->text);
1569 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1570 d->richTextAsImage = enableImageCache();
1572 d->rightToLeftText = d->text.isRightToLeft();
1574 d->determineHorizontalAlignment();
1578 emit textFormatChanged(d->format);
1582 \qmlproperty enumeration QtQuick2::Text::elide
1584 Set this property to elide parts of the text fit to the Text item's width.
1585 The text will only elide if an explicit width has been set.
1587 This property cannot be used with rich text.
1591 \o Text.ElideNone - the default
1597 If this property is set to Text.ElideRight, it can be used with multiline
1598 text. The text will only elide if \c maximumLineCount, or \c height has been set.
1599 If both \c maximumLineCount and \c height are set, \c maximumLineCount will
1600 apply unless the lines do not fit in the height allowed.
1602 If the text is a multi-length string, and the mode is not \c Text.ElideNone,
1603 the first string that fits will be used, otherwise the last will be elided.
1605 Multi-length strings are ordered from longest to shortest, separated by the
1606 Unicode "String Terminator" character \c U009C (write this in QML with \c{"\u009C"} or \c{"\x9C"}).
1608 QQuickText::TextElideMode QQuickText::elideMode() const
1610 Q_D(const QQuickText);
1611 return d->elideMode;
1614 void QQuickText::setElideMode(QQuickText::TextElideMode mode)
1617 if (mode == d->elideMode)
1620 d->elideMode = mode;
1623 emit elideModeChanged(d->elideMode);
1627 QRectF QQuickText::boundingRect() const
1629 Q_D(const QQuickText);
1631 QRect rect = d->layedOutTextRect;
1632 if (d->style != Normal)
1633 rect.adjust(-1, 0, 1, 2);
1635 // Could include font max left/right bearings to either side of rectangle.
1638 switch (d->vAlign) {
1642 rect.moveTop(h - rect.height());
1645 rect.moveTop((h - rect.height()) / 2);
1649 return QRectF(rect);
1653 void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
1656 bool widthChanged = newGeometry.width() != oldGeometry.width();
1657 bool heightChanged = newGeometry.height() != oldGeometry.height();
1658 bool leftAligned = effectiveHAlign() == QQuickText::AlignLeft;
1659 bool wrapped = d->wrapMode != QQuickText::NoWrap;
1660 bool elide = d->elideMode != QQuickText::ElideNone;
1662 if ((!widthChanged && !heightChanged) || d->internalWidthUpdate)
1663 goto geomChangeDone;
1665 if (leftAligned && !wrapped && !elide)
1666 goto geomChangeDone; // left aligned unwrapped text without eliding never needs relayout
1668 if (!widthChanged && !wrapped && d->singleline)
1669 goto geomChangeDone; // only height has changed which doesn't affect single line unwrapped text
1671 if (!widthChanged && wrapped && d->elideMode != QQuickText::ElideRight)
1672 goto geomChangeDone; // only height changed and no multiline eliding.
1674 if (leftAligned && d->elideMode == QQuickText::ElideRight && !d->truncated && d->singleline
1675 && !wrapped && newGeometry.width() > oldGeometry.width())
1676 goto geomChangeDone; // Eliding not affected if we're not currently truncated and we get wider.
1678 if (d->elideMode == QQuickText::ElideRight && wrapped && newGeometry.height() > oldGeometry.height()) {
1680 goto geomChangeDone; // Multiline eliding not affected if we're not currently truncated and we get higher.
1681 if (d->maximumLineCountValid && d->lineCount == d->maximumLineCount)
1682 goto geomChangeDone; // Multiline eliding not affected if we're already at max line count and we get higher.
1685 if (d->updateOnComponentComplete || (elide && widthValid())) {
1686 // We need to re-elide
1689 // We just need to re-layout
1694 QQuickItem::geometryChanged(newGeometry, oldGeometry);
1697 QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1702 if (d->text.isEmpty()) {
1707 QRectF bounds = boundingRect();
1709 // We need to make sure the layout is done in the current thread
1710 #if defined(Q_OS_MAC)
1711 d->paintingThread = QThread::currentThread();
1712 if (d->layoutThread != d->paintingThread)
1716 // XXX todo - some styled text can be done by the QQuickTextNode
1717 if (d->richTextAsImage || d->cacheAllTextAsImage || (qmlDisableDistanceField() && d->style != Normal)) {
1718 bool wasDirty = d->textureImageCacheDirty;
1719 d->textureImageCacheDirty = false;
1721 if (d->imageCache.isNull()) {
1726 QSGImageNode *node = 0;
1727 if (!oldNode || d->nodeType != QQuickTextPrivate::NodeIsTexture) {
1729 node = QQuickItemPrivate::get(this)->sceneGraphContext()->createImageNode();
1730 d->texture = new QSGPlainTexture();
1732 d->nodeType = QQuickTextPrivate::NodeIsTexture;
1734 node = static_cast<QSGImageNode *>(oldNode);
1735 Q_ASSERT(d->texture);
1739 qobject_cast<QSGPlainTexture *>(d->texture)->setImage(d->imageCache.toImage());
1740 node->setTexture(0);
1741 node->setTexture(d->texture);
1744 node->setTargetRect(QRectF(bounds.x(), bounds.y(), d->imageCache.width(), d->imageCache.height()));
1745 node->setSourceRect(QRectF(0, 0, 1, 1));
1746 node->setHorizontalWrapMode(QSGTexture::ClampToEdge);
1747 node->setVerticalWrapMode(QSGTexture::ClampToEdge);
1748 node->setFiltering(QSGTexture::Linear); // Nonsmooth text just ugly, so don't do that..
1754 QQuickTextNode *node = 0;
1755 if (!oldNode || d->nodeType != QQuickTextPrivate::NodeIsText) {
1757 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1758 d->nodeType = QQuickTextPrivate::NodeIsText;
1760 node = static_cast<QQuickTextNode *>(oldNode);
1763 node->deleteContent();
1764 node->setMatrix(QMatrix4x4());
1768 node->addTextDocument(bounds.topLeft(), d->doc, d->color, d->style, d->styleColor);
1770 } else if (d->elideMode == QQuickText::ElideNone || bounds.width() > 0.) {
1771 node->addTextLayout(QPoint(0, bounds.y()), &d->layout, d->color, d->style, d->styleColor);
1772 if (d->elipsisLayout)
1773 node->addTextLayout(QPoint(0, bounds.y()), d->elipsisLayout, d->color, d->style, d->styleColor);
1780 bool QQuickText::event(QEvent *e)
1783 if (e->type() == QEvent::User) {
1784 d->checkImageCache();
1787 return QQuickImplicitSizeItem::event(e);
1792 \qmlproperty real QtQuick2::Text::paintedWidth
1794 Returns the width of the text, including width past the width
1795 which is covered due to insufficient wrapping if WrapMode is set.
1797 qreal QQuickText::paintedWidth() const
1799 Q_D(const QQuickText);
1800 return d->paintedSize.width();
1804 \qmlproperty real QtQuick2::Text::paintedHeight
1806 Returns the height of the text, including height past the height
1807 which is covered due to there being more text than fits in the set height.
1809 qreal QQuickText::paintedHeight() const
1811 Q_D(const QQuickText);
1812 return d->paintedSize.height();
1816 \qmlproperty real QtQuick2::Text::lineHeight
1818 Sets the line height for the text.
1819 The value can be in pixels or a multiplier depending on lineHeightMode.
1821 The default value is a multiplier of 1.0.
1822 The line height must be a positive value.
1824 qreal QQuickText::lineHeight() const
1826 Q_D(const QQuickText);
1827 return d->lineHeight;
1830 void QQuickText::setLineHeight(qreal lineHeight)
1834 if ((d->lineHeight == lineHeight) || (lineHeight < 0.0))
1837 d->lineHeight = lineHeight;
1839 emit lineHeightChanged(lineHeight);
1843 \qmlproperty enumeration QtQuick2::Text::lineHeightMode
1845 This property determines how the line height is specified.
1846 The possible values are:
1849 \o Text.ProportionalHeight (default) - this sets the spacing proportional to the
1850 line (as a multiplier). For example, set to 2 for double spacing.
1851 \o Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
1854 QQuickText::LineHeightMode QQuickText::lineHeightMode() const
1856 Q_D(const QQuickText);
1857 return d->lineHeightMode;
1860 void QQuickText::setLineHeightMode(LineHeightMode mode)
1863 if (mode == d->lineHeightMode)
1866 d->lineHeightMode = mode;
1869 emit lineHeightModeChanged(mode);
1873 Returns the number of resources (images) that are being loaded asynchronously.
1875 int QQuickText::resourcesLoading() const
1877 Q_D(const QQuickText);
1878 return d->doc ? d->doc->resourcesLoading() : 0;
1882 void QQuickText::componentComplete()
1885 if (d->updateOnComponentComplete) {
1888 d->doc->setText(d->text);
1889 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1890 d->richTextAsImage = enableImageCache();
1892 d->rightToLeftText = d->text.isRightToLeft();
1894 d->determineHorizontalAlignment();
1896 QQuickItem::componentComplete();
1897 if (d->updateOnComponentComplete)
1902 QString QQuickTextPrivate::anchorAt(const QPointF &mousePos)
1905 for (int i = 0; i < layout.lineCount(); ++i) {
1906 QTextLine line = layout.lineAt(i);
1907 if (line.naturalTextRect().contains(mousePos)) {
1908 int charPos = line.xToCursor(mousePos.x());
1909 foreach (const QTextLayout::FormatRange &formatRange, layout.additionalFormats()) {
1910 if (formatRange.format.isAnchor()
1911 && charPos >= formatRange.start
1912 && charPos <= formatRange.start + formatRange.length) {
1913 return formatRange.format.anchorHref();
1923 bool QQuickTextPrivate::isLinkActivatedConnected()
1925 static int idx = this->signalIndex("linkActivated(QString)");
1926 return this->isSignalConnected(idx);
1930 void QQuickText::mousePressEvent(QMouseEvent *event)
1934 if (d->isLinkActivatedConnected()) {
1936 d->activeLink = d->anchorAt(event->localPos());
1937 else if (d->richText && d->doc)
1938 d->activeLink = d->doc->documentLayout()->anchorAt(event->localPos());
1941 if (d->activeLink.isEmpty())
1942 event->setAccepted(false);
1944 // ### may malfunction if two of the same links are clicked & dragged onto each other)
1946 if (!event->isAccepted())
1947 QQuickItem::mousePressEvent(event);
1952 void QQuickText::mouseReleaseEvent(QMouseEvent *event)
1956 // ### confirm the link, and send a signal out
1959 if (d->isLinkActivatedConnected()) {
1961 link = d->anchorAt(event->localPos());
1962 else if (d->richText && d->doc)
1963 link = d->doc->documentLayout()->anchorAt(event->localPos());
1966 if (!link.isEmpty() && d->activeLink == link)
1967 emit linkActivated(d->activeLink);
1969 event->setAccepted(false);
1971 if (!event->isAccepted())
1972 QQuickItem::mouseReleaseEvent(event);