1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtQml module of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include "qquicktext_p.h"
43
#include "qquicktext_p_p.h"
45
#include <QtQuick/private/qsgcontext_p.h>
46
#include <private/qqmlglobal_p.h>
47
#include <private/qsgadaptationlayer_p.h>
48
#include "qquicktextnode_p.h"
49
#include "qquickimage_p_p.h"
50
#include "qquicktextutil_p.h"
52
#include <QtQuick/private/qsgtexture_p.h>
54
#include <QtQml/qqmlinfo.h>
55
#include <QtGui/qevent.h>
56
#include <QtGui/qabstracttextdocumentlayout.h>
57
#include <QtGui/qpainter.h>
58
#include <QtGui/qtextdocument.h>
59
#include <QtGui/qtextobject.h>
60
#include <QtGui/qtextcursor.h>
61
#include <QtGui/qguiapplication.h>
62
#include <QtGui/qinputmethod.h>
64
#include <private/qtextengine_p.h>
65
#include <private/qquickstyledtext_p.h>
66
#include <QtQuick/private/qquickpixmapcache_p.h>
74
const QChar QQuickTextPrivate::elideChar = QChar(0x2026);
76
QQuickTextPrivate::QQuickTextPrivate()
77
: elideLayout(0), textLine(0), lineWidth(0)
78
, color(0xFF000000), linkColor(0xFF0000FF), styleColor(0xFF000000)
79
, lineCount(1), multilengthEos(-1)
80
, elideMode(QQuickText::ElideNone), hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop)
81
, format(QQuickText::AutoText), wrapMode(QQuickText::NoWrap)
82
, style(QQuickText::Normal)
83
, renderType(QQuickText::QtRendering)
84
, updateType(UpdatePaintNode)
85
, maximumLineCountValid(false), updateOnComponentComplete(true), richText(false)
86
, styledText(false), widthExceeded(false), heightExceeded(false), internalWidthUpdate(false)
87
, requireImplicitSize(false), implicitWidthValid(false), implicitHeightValid(false)
88
, truncated(false), hAlignImplicit(true), rightToLeftText(false)
89
, layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false), formatModifiesFontSize(false)
93
QQuickTextPrivate::ExtraData::ExtraData()
96
, minimumPixelSize(12)
97
, minimumPointSize(12)
98
, nbActiveDownloads(0)
99
, maximumLineCount(INT_MAX)
100
, lineHeightMode(QQuickText::ProportionalHeight)
101
, fontSizeMode(QQuickText::FixedSize)
105
void QQuickTextPrivate::init()
108
q->setAcceptedMouseButtons(Qt::LeftButton);
109
q->setFlag(QQuickItem::ItemHasContents);
112
QQuickTextDocumentWithImageResources::QQuickTextDocumentWithImageResources(QQuickItem *parent)
113
: QTextDocument(parent), outstanding(0)
115
setUndoRedoEnabled(false);
116
documentLayout()->registerHandler(QTextFormat::ImageObject, this);
119
QQuickTextDocumentWithImageResources::~QQuickTextDocumentWithImageResources()
121
if (!m_resources.isEmpty())
122
qDeleteAll(m_resources);
125
QVariant QQuickTextDocumentWithImageResources::loadResource(int type, const QUrl &name)
127
QQmlContext *context = qmlContext(parent());
128
QUrl url = m_baseUrl.resolved(name);
130
if (type == QTextDocument::ImageResource) {
131
QQuickPixmap *p = loadPixmap(context, url);
135
return QTextDocument::loadResource(type,url); // The *resolved* URL
138
void QQuickTextDocumentWithImageResources::requestFinished()
141
if (outstanding == 0) {
142
markContentsDirty(0, characterCount());
147
void QQuickTextDocumentWithImageResources::clear()
151
QTextDocument::clear();
155
QSizeF QQuickTextDocumentWithImageResources::intrinsicSize(
156
QTextDocument *, int, const QTextFormat &format)
158
if (format.isImageFormat()) {
159
QTextImageFormat imageFormat = format.toImageFormat();
161
const bool hasWidth = imageFormat.hasProperty(QTextFormat::ImageWidth);
162
const int width = qRound(imageFormat.width());
163
const bool hasHeight = imageFormat.hasProperty(QTextFormat::ImageHeight);
164
const int height = qRound(imageFormat.height());
166
QSizeF size(width, height);
167
if (!hasWidth || !hasHeight) {
168
QQmlContext *context = qmlContext(parent());
169
QUrl url = m_baseUrl.resolved(QUrl(imageFormat.name()));
171
QQuickPixmap *p = loadPixmap(context, url);
179
QSize implicitSize = p->implicitSize();
183
size.setWidth(implicitSize.width());
185
size.setWidth(qRound(height * (implicitSize.width() / (qreal) implicitSize.height())));
189
size.setHeight(implicitSize.height());
191
size.setHeight(qRound(width * (implicitSize.height() / (qreal) implicitSize.width())));
199
void QQuickTextDocumentWithImageResources::drawObject(
200
QPainter *, const QRectF &, QTextDocument *, int, const QTextFormat &)
204
QImage QQuickTextDocumentWithImageResources::image(const QTextImageFormat &format)
206
QQmlContext *context = qmlContext(parent());
207
QUrl url = m_baseUrl.resolved(QUrl(format.name()));
209
QQuickPixmap *p = loadPixmap(context, url);
213
void QQuickTextDocumentWithImageResources::setBaseUrl(const QUrl &url, bool clear)
218
markContentsDirty(0, characterCount());
222
QQuickPixmap *QQuickTextDocumentWithImageResources::loadPixmap(
223
QQmlContext *context, const QUrl &url)
226
QHash<QUrl, QQuickPixmap *>::Iterator iter = m_resources.find(url);
228
if (iter == m_resources.end()) {
229
QQuickPixmap *p = new QQuickPixmap(context->engine(), url);
230
iter = m_resources.insert(url, p);
232
if (p->isLoading()) {
233
p->connectFinished(this, SLOT(requestFinished()));
238
QQuickPixmap *p = *iter;
240
if (!errors.contains(url)) {
242
qmlInfo(parent()) << p->error();
248
void QQuickTextDocumentWithImageResources::clearResources()
250
foreach (QQuickPixmap *pixmap, m_resources)
252
qDeleteAll(m_resources);
257
void QQuickTextDocumentWithImageResources::setText(const QString &text)
261
#ifndef QT_NO_TEXTHTMLPARSER
268
QSet<QUrl> QQuickTextDocumentWithImageResources::errors;
270
QQuickTextPrivate::~QQuickTextPrivate()
273
delete textLine; textLine = 0;
278
qreal QQuickTextPrivate::getImplicitWidth() const
280
if (!requireImplicitSize) {
281
// We don't calculate implicitWidth unless it is required.
282
// We need to force a size update now to ensure implicitWidth is calculated
283
QQuickTextPrivate *me = const_cast<QQuickTextPrivate*>(this);
284
me->requireImplicitSize = true;
287
return implicitWidth;
290
qreal QQuickTextPrivate::getImplicitHeight() const
292
if (!requireImplicitSize) {
293
QQuickTextPrivate *me = const_cast<QQuickTextPrivate*>(this);
294
me->requireImplicitSize = true;
297
return implicitHeight;
301
\qmlproperty enumeration QtQuick2::Text::renderType
303
Override the default rendering type for this component.
305
Supported render types are:
307
\li Text.QtRendering - the default
308
\li Text.NativeRendering
311
Select Text.NativeRendering if you prefer text to look native on the target platform and do
312
not require advanced features such as transformation of the text. Using such features in
313
combination with the NativeRendering render type will lend poor and sometimes pixelated
316
QQuickText::RenderType QQuickText::renderType() const
318
Q_D(const QQuickText);
319
return d->renderType;
322
void QQuickText::setRenderType(QQuickText::RenderType renderType)
325
if (d->renderType == renderType)
328
d->renderType = renderType;
329
emit renderTypeChanged();
331
if (isComponentComplete())
335
void QQuickText::q_imagesLoaded()
341
void QQuickTextPrivate::updateLayout()
344
if (!q->isComponentComplete()) {
345
updateOnComponentComplete = true;
348
updateOnComponentComplete = false;
349
layoutTextElided = false;
351
if (!visibleImgTags.isEmpty())
352
visibleImgTags.clear();
353
needToUpdateLayout = false;
355
// Setup instance of QTextLayout for all cases other than richtext
357
if (textHasChanged) {
358
if (styledText && !text.isEmpty()) {
359
layout.setFont(font);
360
// needs temporary bool because formatModifiesFontSize is in a bit-field
361
bool fontSizeModified = false;
362
QQuickStyledText::parse(text, layout, imgTags, q->baseUrl(), qmlContext(q), !maximumLineCountValid, &fontSizeModified);
363
formatModifiesFontSize = fontSizeModified;
366
layout.clearAdditionalFormats();
368
elideLayout->clearAdditionalFormats();
370
multilengthEos = tmp.indexOf(QLatin1Char('\x9c'));
371
if (multilengthEos != -1) {
372
tmp = tmp.mid(0, multilengthEos);
373
tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
374
} else if (tmp.contains(QLatin1Char('\n'))) {
375
// Replace always does a detach. Checking for the new line character first
376
// means iterating over those items again if found but prevents a realloc
378
tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
382
textHasChanged = false;
386
QTextBlockFormat::LineHeightTypes type;
387
type = lineHeightMode() == QQuickText::FixedHeight ? QTextBlockFormat::FixedHeight : QTextBlockFormat::ProportionalHeight;
388
QTextBlockFormat blockFormat;
389
blockFormat.setLineHeight((lineHeightMode() == QQuickText::FixedHeight ? lineHeight() : lineHeight() * 100), type);
390
for (QTextBlock it = extra->doc->begin(); it != extra->doc->end(); it = it.next()) {
391
QTextCursor cursor(it);
392
cursor.mergeBlockFormat(blockFormat);
398
if (needToUpdateLayout) {
399
needToUpdateLayout = false;
400
textHasChanged = true;
405
void QQuickText::imageDownloadFinished()
409
(d->extra->nbActiveDownloads)--;
411
// when all the remote images have been downloaded,
412
// if one of the sizes was not specified at parsing time
413
// we use the implicit size from pixmapcache and re-layout.
415
if (d->extra.isAllocated() && d->extra->nbActiveDownloads == 0) {
416
bool needToUpdateLayout = false;
417
foreach (QQuickStyledTextImgTag *img, d->visibleImgTags) {
418
if (!img->size.isValid()) {
419
img->size = img->pix->implicitSize();
420
needToUpdateLayout = true;
424
if (needToUpdateLayout) {
425
d->textHasChanged = true;
428
d->updateType = QQuickTextPrivate::UpdatePaintNode;
434
void QQuickTextPrivate::updateBaseline(qreal baseline, qreal dy)
440
if (q->heightValid()) {
441
if (vAlign == QQuickText::AlignBottom)
443
else if (vAlign == QQuickText::AlignVCenter)
447
q->setBaselineOffset(baseline + yoff);
450
void QQuickTextPrivate::updateSize()
454
if (!q->isComponentComplete()) {
455
updateOnComponentComplete = true;
459
if (!requireImplicitSize) {
460
emit q->implicitWidthChanged();
461
emit q->implicitHeightChanged();
462
// if the implicitWidth is used, then updateSize() has already been called (recursively)
463
if (requireImplicitSize)
467
if (text.isEmpty() && !isLineLaidOutConnected() && fontSizeMode() == QQuickText::FixedSize) {
468
// How much more expensive is it to just do a full layout on an empty string here?
469
// There may be subtle differences in the height and baseline calculations between
470
// QTextLayout and QFontMetrics and the number of variables that can affect the size
471
// and position of a line is increasing.
472
QFontMetricsF fm(font);
473
qreal fontHeight = qCeil(fm.height()); // QScriptLine and therefore QTextLine rounds up
474
if (!richText) { // line height, so we will as well.
475
fontHeight = lineHeightMode() == QQuickText::FixedHeight
477
: fontHeight * lineHeight();
479
updateBaseline(fm.ascent(), q->height() - fontHeight);
480
q->setImplicitSize(0, fontHeight);
481
layedOutTextRect = QRectF(0, 0, 0, fontHeight);
482
emit q->contentSizeChanged();
483
updateType = UpdatePaintNode;
489
QSizeF previousSize = layedOutTextRect.size();
491
//setup instance of QTextLayout for all cases other than richtext
494
QRectF textRect = setupTextLayout(&baseline);
496
if (internalWidthUpdate) // probably the result of a binding loop, but by letting it
497
return; // get this far we'll get a warning to that effect if it is.
499
layedOutTextRect = textRect;
500
size = textRect.size();
501
updateBaseline(baseline, q->height() - size.height());
503
widthExceeded = true; // always relayout rich text on width changes..
504
heightExceeded = false; // rich text layout isn't affected by height changes.
506
extra->doc->setDefaultFont(font);
507
QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign();
508
if (rightToLeftText) {
509
if (horizontalAlignment == QQuickText::AlignLeft)
510
horizontalAlignment = QQuickText::AlignRight;
511
else if (horizontalAlignment == QQuickText::AlignRight)
512
horizontalAlignment = QQuickText::AlignLeft;
515
option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
516
option.setWrapMode(QTextOption::WrapMode(wrapMode));
517
option.setUseDesignMetrics(renderType != QQuickText::NativeRendering);
518
extra->doc->setDefaultTextOption(option);
519
qreal naturalWidth = 0;
520
if (requireImplicitSize && q->widthValid()) {
521
extra->doc->setTextWidth(-1);
522
naturalWidth = extra->doc->idealWidth();
523
const bool wasInLayout = internalWidthUpdate;
524
internalWidthUpdate = true;
525
q->setImplicitWidth(naturalWidth);
526
internalWidthUpdate = wasInLayout;
528
if (internalWidthUpdate)
530
if (wrapMode != QQuickText::NoWrap && q->widthValid())
531
extra->doc->setTextWidth(q->width());
533
extra->doc->setTextWidth(extra->doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
534
widthExceeded = extra->doc->textWidth() < extra->doc->idealWidth();
535
QSizeF dsize = extra->doc->size();
536
layedOutTextRect = QRectF(QPointF(0,0), dsize);
537
size = QSizeF(extra->doc->idealWidth(),dsize.height());
539
QFontMetricsF fm(font);
540
updateBaseline(fm.ascent(), q->height() - size.height());
542
//### need to confirm cost of always setting these for richText
543
internalWidthUpdate = true;
545
if (!q->widthValid())
546
iWidth = size.width();
548
q->setImplicitSize(iWidth, size.height());
549
internalWidthUpdate = false;
552
q->setImplicitHeight(size.height());
555
if (layedOutTextRect.size() != previousSize)
556
emit q->contentSizeChanged();
557
updateType = UpdatePaintNode;
561
QQuickTextLine::QQuickTextLine()
562
: QObject(), m_line(0), m_height(0)
566
void QQuickTextLine::setLine(QTextLine *line)
571
void QQuickTextLine::setLineOffset(int offset)
573
m_lineOffset = offset;
576
int QQuickTextLine::number() const
579
return m_line->lineNumber() + m_lineOffset;
583
qreal QQuickTextLine::width() const
586
return m_line->width();
590
void QQuickTextLine::setWidth(qreal width)
593
m_line->setLineWidth(width);
596
qreal QQuickTextLine::height() const
601
return m_line->height();
605
void QQuickTextLine::setHeight(qreal height)
608
m_line->setPosition(QPointF(m_line->x(), m_line->y() - m_line->height() + height));
612
qreal QQuickTextLine::x() const
619
void QQuickTextLine::setX(qreal x)
622
m_line->setPosition(QPointF(x, m_line->y()));
625
qreal QQuickTextLine::y() const
632
void QQuickTextLine::setY(qreal y)
635
m_line->setPosition(QPointF(m_line->x(), y));
639
\qmlmethod QtQuick2::Text::doLayout()
641
Triggers a re-layout of the displayed text.
643
void QQuickText::doLayout()
649
bool QQuickTextPrivate::isLineLaidOutConnected()
652
IS_SIGNAL_CONNECTED(q, QQuickText, lineLaidOut, (QQuickTextLine *));
655
void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset)
660
textLine = new QQuickTextLine;
661
textLine->setLine(&line);
662
textLine->setY(height);
663
textLine->setHeight(0);
664
textLine->setLineOffset(lineOffset);
666
// use the text item's width by default if it has one and wrap is on
667
if (q->widthValid() && q->wrapMode() != QQuickText::NoWrap)
668
textLine->setWidth(q->width());
670
textLine->setWidth(INT_MAX);
671
if (lineHeight() != 1.0)
672
textLine->setHeight((lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : line.height() * lineHeight());
674
emit q->lineLaidOut(textLine);
676
height += textLine->height();
679
void QQuickTextPrivate::elideFormats(
680
const int start, const int length, int offset, QList<QTextLayout::FormatRange> *elidedFormats)
682
const int end = start + length;
683
QList<QTextLayout::FormatRange> formats = layout.additionalFormats();
684
for (int i = 0; i < formats.count(); ++i) {
685
QTextLayout::FormatRange format = formats.at(i);
686
const int formatLength = qMin(format.start + format.length, end) - qMax(format.start, start);
687
if (formatLength > 0) {
688
format.start = qMax(offset, format.start - start + offset);
689
format.length = formatLength;
690
elidedFormats->append(format);
695
QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine) const
698
return layout.engine()->elidedText(
699
Qt::TextElideMode(elideMode),
700
QFixed::fromReal(lineWidth),
703
line.textLength() + nextLine->textLength());
705
QString elideText = layout.text().mid(line.textStart(), line.textLength());
707
// QFontMetrics won't help eliding styled text.
708
elideText[elideText.length() - 1] = elideChar;
709
// Appending the elide character may push the line over the maximum width
710
// in which case the elided text will need to be elided.
711
QFontMetricsF metrics(layout.font());
712
if (metrics.width(elideChar) + line.naturalTextWidth() >= lineWidth)
713
elideText = metrics.elidedText(elideText, Qt::TextElideMode(elideMode), lineWidth);
720
Lays out the QQuickTextPrivate::layout QTextLayout in the constraints of the QQuickText.
722
Returns the size of the final text. This can be used to position the text vertically (the text is
723
already absolutely positioned horizontally).
726
QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
730
bool singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
731
bool multilineElide = elideMode == QQuickText::ElideRight
733
&& (q->heightValid() || maximumLineCountValid);
735
if ((!requireImplicitSize || (implicitWidthValid && implicitHeightValid))
736
&& ((singlelineElide && q->width() <= 0.) || (multilineElide && q->heightValid() && q->height() <= 0.))) {
737
// we are elided and we have a zero width or height
738
widthExceeded = q->widthValid() && q->width() <= 0.;
739
heightExceeded = q->heightValid() && q->height() <= 0.;
743
emit q->truncatedChanged();
747
emit q->lineCountChanged();
750
QFontMetricsF fm(font);
751
qreal height = (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : qCeil(fm.height()) * lineHeight();
752
*baseline = fm.ascent();
753
return QRectF(0, 0, 0, height);
756
bool shouldUseDesignMetrics = renderType != QQuickText::NativeRendering;
758
layout.setCacheEnabled(true);
759
QTextOption textOption = layout.textOption();
760
if (textOption.alignment() != q->effectiveHAlign()
761
|| textOption.wrapMode() != QTextOption::WrapMode(wrapMode)
762
|| textOption.useDesignMetrics() != shouldUseDesignMetrics) {
763
textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
764
textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
765
textOption.setUseDesignMetrics(shouldUseDesignMetrics);
766
layout.setTextOption(textOption);
768
if (layout.font() != font)
769
layout.setFont(font);
771
lineWidth = (q->widthValid() || implicitWidthValid) && q->width() > 0
774
qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX;
776
const bool customLayout = isLineLaidOutConnected();
777
const bool wasTruncated = truncated;
779
bool canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
781
bool horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
782
bool verticalFit = fontSizeMode() & QQuickText::VerticalFit
783
&& (q->heightValid() || (maximumLineCountValid && canWrap));
785
const bool pixelSize = font.pixelSize() != -1;
786
QString layoutText = layout.text();
788
int largeFont = pixelSize ? font.pixelSize() : font.pointSize();
789
int smallFont = fontSizeMode() != QQuickText::FixedSize
790
? qMin(pixelSize ? minimumPixelSize() : minimumPointSize(), largeFont)
792
int scaledFontSize = largeFont;
794
widthExceeded = q->width() <= 0 && (singlelineElide || canWrap || horizontalFit);
795
heightExceeded = q->height() <= 0 && (multilineElide || verticalFit);
799
QFont scaledFont = font;
801
int visibleCount = 0;
809
int eos = multilengthEos;
811
// Repeated layouts with reduced font sizes or abbreviated strings may be required if the text
812
// doesn't fit within the item dimensions, or a binding to implicitWidth/Height changes
813
// the item dimensions.
817
scaledFont.setPixelSize(scaledFontSize);
819
scaledFont.setPointSize(scaledFontSize);
820
if (layout.font() != scaledFont)
821
layout.setFont(scaledFont);
824
layout.beginLayout();
826
bool wrapped = false;
827
bool truncateHeight = false;
830
int unwrappedLineCount = 1;
831
int maxLineCount = maximumLineCount();
833
qreal naturalHeight = 0;
834
qreal previousHeight = 0;
838
QTextLine line = layout.createLine();
839
for (visibleCount = 1; ; ++visibleCount) {
841
setupCustomLineGeometry(line, naturalHeight);
843
setLineGeometry(line, lineWidth, naturalHeight);
846
unelidedRect = br.united(line.naturalTextRect());
848
// Elide the previous line if the accumulated height of the text exceeds the height
850
if (multilineElide && naturalHeight > maxHeight && visibleCount > 1) {
852
heightExceeded = true;
853
if (eos != -1) // There's an abbreviated string available, skip the rest as it's
854
break; // all going to be discarded.
857
truncateHeight = true;
861
QTextLine previousLine = layout.lineAt(visibleCount - 1);
862
elideText = layoutText.at(line.textStart() - 1) != QChar::LineSeparator
863
? elidedText(lineWidth, previousLine, &line)
864
: elidedText(lineWidth, previousLine);
865
elideStart = previousLine.textStart();
866
// elideEnd isn't required for right eliding.
868
height = previousHeight;
872
const QTextLine previousLine = line;
873
line = layout.createLine();
874
if (!line.isValid()) {
875
if (singlelineElide && visibleCount == 1 && previousLine.naturalTextWidth() > lineWidth) {
876
// Elide a single previousLine of text if its width exceeds the element width.
878
widthExceeded = true;
879
if (eos != -1) // There's an abbreviated string available.
883
elideText = layout.engine()->elidedText(
884
Qt::TextElideMode(elideMode),
885
QFixed::fromReal(lineWidth),
887
previousLine.textStart(),
888
previousLine.textLength());
889
elideStart = previousLine.textStart();
890
elideEnd = elideStart + previousLine.textLength();
893
height = naturalHeight;
897
const bool wrappedLine = layoutText.at(line.textStart() - 1) != QChar::LineSeparator;
898
wrapped |= wrappedLine;
901
++unwrappedLineCount;
903
// Stop if the maximum number of lines has been reached and elide the last line
905
if (visibleCount == maxLineCount) {
907
heightExceeded |= wrapped;
909
if (multilineElide) {
911
if (eos != -1) // There's an abbreviated string available
913
elideText = wrappedLine
914
? elidedText(lineWidth, previousLine, &line)
915
: elidedText(lineWidth, previousLine);
916
elideStart = previousLine.textStart();
917
// elideEnd isn't required for right eliding.
920
height = naturalHeight;
926
previousHeight = height;
927
height = naturalHeight;
929
widthExceeded |= wrapped;
931
// Save the implicit size of the text on the first layout only.
935
// If implicit sizes are required layout any additional lines up to the maximum line
937
if ((requireImplicitSize) && line.isValid() && unwrappedLineCount < maxLineCount) {
938
// Layout the remainder of the wrapped lines up to maxLineCount to get the implicit
940
for (int lineCount = layout.lineCount(); lineCount < maxLineCount; ++lineCount) {
941
line = layout.createLine();
944
if (layoutText.at(line.textStart() - 1) == QChar::LineSeparator)
945
++unwrappedLineCount;
946
setLineGeometry(line, lineWidth, naturalHeight);
949
// Create the remainder of the unwrapped lines up to maxLineCount to get the
951
if (line.isValid() && layoutText.at(line.textStart() + line.textLength()) != QChar::LineSeparator)
952
line = layout.createLine();
953
for (; line.isValid() && unwrappedLineCount <= maxLineCount; ++unwrappedLineCount)
954
line = layout.createLine();
958
const qreal naturalWidth = layout.maximumWidth();
960
bool wasInLayout = internalWidthUpdate;
961
internalWidthUpdate = true;
962
q->setImplicitSize(naturalWidth, naturalHeight);
963
internalWidthUpdate = wasInLayout;
965
// Update any variables that are dependent on the validity of the width or height.
966
singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
967
multilineElide = elideMode == QQuickText::ElideRight
969
&& (q->heightValid() || maximumLineCountValid);
970
canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
972
horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
973
verticalFit = fontSizeMode() & QQuickText::VerticalFit
974
&& (q->heightValid() || (maximumLineCountValid && canWrap));
976
const qreal oldWidth = lineWidth;
977
const qreal oldHeight = maxHeight;
979
lineWidth = q->widthValid() && q->width() > 0 ? q->width() : naturalWidth;
980
maxHeight = q->heightValid() ? q->height() : FLT_MAX;
982
// If the width of the item has changed and it's possible the result of wrapping,
983
// eliding, or scaling has changed do another layout.
984
if ((lineWidth < qMin(oldWidth, naturalWidth) || (widthExceeded && lineWidth > oldWidth))
985
&& (singlelineElide || multilineElide || canWrap || horizontalFit)) {
986
widthExceeded = false;
987
heightExceeded = false;
991
// If the height of the item has changed and it's possible the result of eliding,
992
// line count truncation or scaling has changed, do another layout.
993
if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight))
994
&& (multilineElide || (canWrap && maximumLineCountValid))) {
995
widthExceeded = false;
996
heightExceeded = false;
1000
// If the horizontal alignment is not left and the width was not valid we need to relayout
1001
// now that we know the maximum line width.
1002
if (!implicitWidthValid && lineCount > 1 && q->effectiveHAlign() != QQuickText::AlignLeft) {
1003
widthExceeded = false;
1004
heightExceeded = false;
1011
// If the next needs to be elided and there's an abbreviated string available
1012
// go back and do another layout with the abbreviated string.
1013
if (eos != -1 && elide) {
1014
int start = eos + 1;
1015
eos = text.indexOf(QLatin1Char('\x9c'), start);
1016
layoutText = text.mid(start, eos != -1 ? eos - start : -1);
1017
layoutText.replace(QLatin1Char('\n'), QChar::LineSeparator);
1018
layout.setText(layoutText);
1019
textHasChanged = true;
1025
if (!horizontalFit && !verticalFit)
1028
// Try and find a font size that better fits the dimensions of the element.
1029
if (horizontalFit) {
1030
if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
1031
widthExceeded = true;
1032
largeFont = scaledFontSize - 1;
1033
if (smallFont > largeFont)
1035
scaledFontSize = (smallFont + largeFont) / 2;
1037
scaledFont.setPixelSize(scaledFontSize);
1039
scaledFont.setPointSize(scaledFontSize);
1041
} else if (!verticalFit) {
1042
smallFont = scaledFontSize;
1043
if (smallFont == largeFont)
1045
scaledFontSize = (smallFont + largeFont + 1) / 2;
1050
if (truncateHeight || unelidedRect.height() > maxHeight) {
1051
heightExceeded = true;
1052
largeFont = scaledFontSize - 1;
1053
if (smallFont > largeFont)
1055
scaledFontSize = (smallFont + largeFont) / 2;
1058
smallFont = scaledFontSize;
1059
if (smallFont == largeFont)
1061
scaledFontSize = (smallFont + largeFont + 1) / 2;
1066
implicitWidthValid = true;
1067
implicitHeightValid = true;
1069
if (eos != multilengthEos)
1074
elideLayout = new QTextLayout;
1075
elideLayout->setCacheEnabled(true);
1078
QList<QTextLayout::FormatRange> formats;
1079
switch (elideMode) {
1080
case QQuickText::ElideRight:
1081
elideFormats(elideStart, elideText.length() - 1, 0, &formats);
1083
case QQuickText::ElideLeft:
1084
elideFormats(elideEnd - elideText.length() + 1, elideText.length() - 1, 1, &formats);
1086
case QQuickText::ElideMiddle: {
1087
const int index = elideText.indexOf(elideChar);
1089
elideFormats(elideStart, index, 0, &formats);
1091
elideEnd - elideText.length() + index + 1,
1092
elideText.length() - index - 1,
1101
elideLayout->setAdditionalFormats(formats);
1104
elideLayout->setFont(layout.font());
1105
elideLayout->setTextOption(layout.textOption());
1106
elideLayout->setText(elideText);
1107
elideLayout->beginLayout();
1109
QTextLine elidedLine = elideLayout->createLine();
1110
elidedLine.setPosition(QPointF(0, height));
1112
setupCustomLineGeometry(elidedLine, height, visibleCount - 1);
1114
setLineGeometry(elidedLine, lineWidth, height);
1116
elideLayout->endLayout();
1118
br = br.united(elidedLine.naturalTextRect());
1120
if (visibleCount == 1)
1121
layout.clearLayout();
1127
QTextLine firstLine = visibleCount == 1 && elideLayout
1128
? elideLayout->lineAt(0)
1130
Q_ASSERT(firstLine.isValid());
1131
*baseline = firstLine.y() + firstLine.ascent();
1134
br.setHeight(height);
1136
//Update the number of visible lines
1137
if (lineCount != visibleCount) {
1138
lineCount = visibleCount;
1139
emit q->lineCountChanged();
1142
if (truncated != wasTruncated)
1143
emit q->truncatedChanged();
1148
void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal &height)
1151
line.setLineWidth(lineWidth);
1153
if (imgTags.isEmpty()) {
1154
line.setPosition(QPointF(line.position().x(), height));
1155
height += (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : line.height() * lineHeight();
1160
qreal textHeight = line.height();
1161
qreal totalLineHeight = textHeight;
1163
QList<QQuickStyledTextImgTag *> imagesInLine;
1165
foreach (QQuickStyledTextImgTag *image, imgTags) {
1166
if (image->position >= line.textStart() &&
1167
image->position < line.textStart() + line.textLength()) {
1170
QUrl url = q->baseUrl().resolved(image->url);
1171
image->pix = new QQuickPixmap(qmlEngine(q), url, image->size);
1172
if (image->pix->isLoading()) {
1173
image->pix->connectFinished(q, SLOT(imageDownloadFinished()));
1174
if (!extra.isAllocated() || !extra->nbActiveDownloads)
1175
extra.value().nbActiveDownloads = 0;
1176
extra->nbActiveDownloads++;
1177
} else if (image->pix->isReady()) {
1178
if (!image->size.isValid()) {
1179
image->size = image->pix->implicitSize();
1180
// if the size of the image was not explicitly set, we need to
1181
// call updateLayout() once again.
1182
needToUpdateLayout = true;
1184
} else if (image->pix->isError()) {
1185
qmlInfo(q) << image->pix->error();
1189
qreal ih = qreal(image->size.height());
1190
if (image->align == QQuickStyledTextImgTag::Top)
1192
else if (image->align == QQuickStyledTextImgTag::Middle)
1193
image->pos.setY((textHeight / 2.0) - (ih / 2.0));
1195
image->pos.setY(textHeight - ih);
1196
imagesInLine << image;
1197
textTop = qMax(textTop, qAbs(image->pos.y()));
1201
foreach (QQuickStyledTextImgTag *image, imagesInLine) {
1202
totalLineHeight = qMax(totalLineHeight, textTop + image->pos.y() + image->size.height());
1203
image->pos.setX(line.cursorToX(image->position));
1204
image->pos.setY(image->pos.y() + height + textTop);
1205
visibleImgTags << image;
1208
line.setPosition(QPointF(line.position().x(), height + textTop));
1209
height += (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : totalLineHeight * lineHeight();
1213
Ensures the QQuickTextPrivate::doc variable is set to a valid text document
1215
void QQuickTextPrivate::ensureDoc()
1217
if (!extra.isAllocated() || !extra->doc) {
1219
extra.value().doc = new QQuickTextDocumentWithImageResources(q);
1220
extra->doc->setPageSize(QSizeF(0, 0));
1221
extra->doc->setDocumentMargin(0);
1222
extra->doc->setBaseUrl(q->baseUrl());
1223
qmlobject_connect(extra->doc, QQuickTextDocumentWithImageResources, SIGNAL(imagesLoaded()),
1224
q, QQuickText, SLOT(q_imagesLoaded()));
1230
\instantiates QQuickText
1231
\inqmlmodule QtQuick 2
1232
\ingroup qtquick-visual
1234
\brief Specifies how to add formatted text to a scene
1236
Text items can display both plain and rich text. For example, red text with
1237
a specific font and size can be defined like this:
1241
text: "Hello World!"
1242
font.family: "Helvetica"
1248
Rich text is defined using HTML-style markup:
1252
text: "<b>Hello</b> <i>World!</i>"
1256
\image declarative-text.png
1258
If height and width are not explicitly set, Text will attempt to determine how
1259
much room is needed and set it accordingly. Unless \l wrapMode is set, it will always
1260
prefer width to height (all text will be placed on a single line).
1262
The \l elide property can alternatively be used to fit a single line of
1263
plain text to a set width.
1265
Note that the \l{Supported HTML Subset} is limited. Also, if the text contains
1266
HTML img tags that load remote images, the text is reloaded.
1268
Text provides read-only text. For editable text, see \l TextEdit.
1270
\sa {declarative/text/fonts}{Fonts example}
1272
QQuickText::QQuickText(QQuickItem *parent)
1273
: QQuickImplicitSizeItem(*(new QQuickTextPrivate), parent)
1279
QQuickText::~QQuickText()
1284
\qmlproperty bool QtQuick2::Text::clip
1285
This property holds whether the text is clipped.
1287
Note that if the text does not fit in the bounding rectangle it will be abruptly chopped.
1289
If you want to display potentially long text in a limited space, you probably want to use \c elide instead.
1293
\qmlsignal QtQuick2::Text::onLineLaidOut(object line)
1295
This handler is called for each line of text that is laid out during the layout
1296
process. The specified \a line object provides more details about the line that
1297
is currently being laid out.
1299
This gives the opportunity to position and resize a line as it is being laid out.
1300
It can for example be used to create columns or lay out text around objects.
1302
The properties of the specified \a line object are:
1304
\li number (read-only)
1311
For example, this will move the first 5 lines of a Text item by 100 pixels to the right:
1314
if (line.number < 5) {
1315
line.x = line.x + 100
1316
line.width = line.width - 100
1323
\qmlsignal QtQuick2::Text::onLinkActivated(string link)
1325
This handler is called when the user clicks on a link embedded in the text.
1326
The link must be in rich text or HTML format and the
1327
\a link string provides access to the particular link.
1329
\snippet qml/text/onLinkActivated.qml 0
1331
The example code will display the text
1332
"The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}."
1334
Clicking on the highlighted link will output
1335
\tt{http://qt.nokia.com link activated} to the console.
1339
\qmlproperty string QtQuick2::Text::font.family
1341
Sets the family name of the font.
1343
The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
1344
If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
1345
If the family isn't available a family will be set using the font matching algorithm.
1349
\qmlproperty bool QtQuick2::Text::font.bold
1351
Sets whether the font weight is bold.
1355
\qmlproperty enumeration QtQuick2::Text::font.weight
1357
Sets the font's weight.
1359
The weight can be one of:
1362
\li Font.Normal - the default
1369
Text { text: "Hello"; font.weight: Font.DemiBold }
1374
\qmlproperty bool QtQuick2::Text::font.italic
1376
Sets whether the font has an italic style.
1380
\qmlproperty bool QtQuick2::Text::font.underline
1382
Sets whether the text is underlined.
1386
\qmlproperty bool QtQuick2::Text::font.strikeout
1388
Sets whether the font has a strikeout style.
1392
\qmlproperty real QtQuick2::Text::font.pointSize
1394
Sets the font size in points. The point size must be greater than zero.
1398
\qmlproperty int QtQuick2::Text::font.pixelSize
1400
Sets the font size in pixels.
1402
Using this function makes the font device dependent.
1403
Use \c pointSize to set the size of the font in a device independent manner.
1407
\qmlproperty real QtQuick2::Text::font.letterSpacing
1409
Sets the letter spacing for the font.
1411
Letter spacing changes the default spacing between individual letters in the font.
1412
A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
1416
\qmlproperty real QtQuick2::Text::font.wordSpacing
1418
Sets the word spacing for the font.
1420
Word spacing changes the default spacing between individual words.
1421
A positive value increases the word spacing by a corresponding amount of pixels,
1422
while a negative value decreases the inter-word spacing accordingly.
1426
\qmlproperty enumeration QtQuick2::Text::font.capitalization
1428
Sets the capitalization for the text.
1431
\li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
1432
\li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
1433
\li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
1434
\li Font.SmallCaps - This alters the text to be rendered in small-caps type.
1435
\li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
1439
Text { text: "Hello"; font.capitalization: Font.AllLowercase }
1442
QFont QQuickText::font() const
1444
Q_D(const QQuickText);
1445
return d->sourceFont;
1448
void QQuickText::setFont(const QFont &font)
1451
if (d->sourceFont == font)
1454
d->sourceFont = font;
1455
QFont oldFont = d->font;
1458
if (d->font.pointSizeF() != -1) {
1460
qreal size = qRound(d->font.pointSizeF()*2.0);
1461
d->font.setPointSizeF(size/2.0);
1464
if (oldFont != d->font) {
1465
// if the format changes the size of the text
1466
// with headings or <font> tag, we need to re-parse
1467
if (d->formatModifiesFontSize)
1468
d->textHasChanged = true;
1469
d->implicitWidthValid = false;
1470
d->implicitHeightValid = false;
1474
emit fontChanged(d->sourceFont);
1478
\qmlproperty string QtQuick2::Text::text
1480
The text to display. Text supports both plain and rich text strings.
1482
The item will try to automatically determine whether the text should
1483
be treated as styled text. This determination is made using Qt::mightBeRichText().
1485
QString QQuickText::text() const
1487
Q_D(const QQuickText);
1491
void QQuickText::setText(const QString &n)
1497
d->richText = d->format == RichText;
1498
d->styledText = d->format == StyledText || (d->format == AutoText && Qt::mightBeRichText(n));
1500
if (isComponentComplete()) {
1503
d->extra->doc->setText(n);
1504
d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
1506
d->rightToLeftText = d->text.isRightToLeft();
1508
d->determineHorizontalAlignment();
1510
d->textHasChanged = true;
1511
d->implicitWidthValid = false;
1512
d->implicitHeightValid = false;
1513
qDeleteAll(d->imgTags);
1516
emit textChanged(d->text);
1520
\qmlproperty color QtQuick2::Text::color
1524
An example of green text defined using hexadecimal notation:
1532
An example of steel blue text defined using an SVG color name:
1540
QColor QQuickText::color() const
1542
Q_D(const QQuickText);
1543
return QColor::fromRgba(d->color);
1546
void QQuickText::setColor(const QColor &color)
1549
QRgb rgb = color.rgba();
1550
if (d->color == rgb)
1554
if (isComponentComplete()) {
1555
d->updateType = QQuickTextPrivate::UpdatePaintNode;
1558
emit colorChanged();
1562
\qmlproperty color QtQuick2::Text::linkColor
1564
The color of links in the text.
1566
This property works with the StyledText \l textFormat, but not with RichText.
1567
Link color in RichText can be specified by including CSS style tags in the
1571
QColor QQuickText::linkColor() const
1573
Q_D(const QQuickText);
1574
return QColor::fromRgba(d->linkColor);
1577
void QQuickText::setLinkColor(const QColor &color)
1580
QRgb rgb = color.rgba();
1581
if (d->linkColor == rgb)
1586
emit linkColorChanged();
1590
\qmlproperty enumeration QtQuick2::Text::style
1592
Set an additional text style.
1594
Supported text styles are:
1596
\li Text.Normal - the default
1604
Text { font.pointSize: 24; text: "Normal" }
1605
Text { font.pointSize: 24; text: "Raised"; style: Text.Raised; styleColor: "#AAAAAA" }
1606
Text { font.pointSize: 24; text: "Outline";style: Text.Outline; styleColor: "red" }
1607
Text { font.pointSize: 24; text: "Sunken"; style: Text.Sunken; styleColor: "#AAAAAA" }
1611
\image declarative-textstyle.png
1613
QQuickText::TextStyle QQuickText::style() const
1615
Q_D(const QQuickText);
1619
void QQuickText::setStyle(QQuickText::TextStyle style)
1622
if (d->style == style)
1626
if (isComponentComplete()) {
1627
d->updateType = QQuickTextPrivate::UpdatePaintNode;
1630
emit styleChanged(d->style);
1634
\qmlproperty color QtQuick2::Text::styleColor
1636
Defines the secondary color used by text styles.
1638
\c styleColor is used as the outline color for outlined text, and as the
1639
shadow color for raised or sunken text. If no style has been set, it is not
1643
Text { font.pointSize: 18; text: "hello"; style: Text.Raised; styleColor: "gray" }
1648
QColor QQuickText::styleColor() const
1650
Q_D(const QQuickText);
1651
return QColor::fromRgba(d->styleColor);
1654
void QQuickText::setStyleColor(const QColor &color)
1657
QRgb rgb = color.rgba();
1658
if (d->styleColor == rgb)
1661
d->styleColor = rgb;
1662
if (isComponentComplete()) {
1663
d->updateType = QQuickTextPrivate::UpdatePaintNode;
1666
emit styleColorChanged();
1670
\qmlproperty enumeration QtQuick2::Text::horizontalAlignment
1671
\qmlproperty enumeration QtQuick2::Text::verticalAlignment
1672
\qmlproperty enumeration QtQuick2::Text::effectiveHorizontalAlignment
1674
Sets the horizontal and vertical alignment of the text within the Text items
1675
width and height. By default, the text is vertically aligned to the top. Horizontal
1676
alignment follows the natural alignment of the text, for example text that is read
1677
from left to right will be aligned to the left.
1679
The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and
1680
\c Text.AlignJustify. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom
1681
and \c Text.AlignVCenter.
1683
Note that for a single line of text, the size of the text is the area of the text. In this common case,
1684
all alignments are equivalent. If you want the text to be, say, centered in its parent, then you will
1685
need to either modify the Item::anchors, or set horizontalAlignment to Text.AlignHCenter and bind the width to
1688
When using the attached property LayoutMirroring::enabled to mirror application
1689
layouts, the horizontal alignment of text will also be mirrored. However, the property
1690
\c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
1691
of Text, use the read-only property \c effectiveHorizontalAlignment.
1693
QQuickText::HAlignment QQuickText::hAlign() const
1695
Q_D(const QQuickText);
1699
void QQuickText::setHAlign(HAlignment align)
1702
bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
1703
d->hAlignImplicit = false;
1704
if (d->setHAlign(align, forceAlign) && isComponentComplete())
1708
void QQuickText::resetHAlign()
1711
d->hAlignImplicit = true;
1712
if (isComponentComplete() && d->determineHorizontalAlignment())
1716
QQuickText::HAlignment QQuickText::effectiveHAlign() const
1718
Q_D(const QQuickText);
1719
QQuickText::HAlignment effectiveAlignment = d->hAlign;
1720
if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
1721
switch (d->hAlign) {
1722
case QQuickText::AlignLeft:
1723
effectiveAlignment = QQuickText::AlignRight;
1725
case QQuickText::AlignRight:
1726
effectiveAlignment = QQuickText::AlignLeft;
1732
return effectiveAlignment;
1735
bool QQuickTextPrivate::setHAlign(QQuickText::HAlignment alignment, bool forceAlign)
1738
if (hAlign != alignment || forceAlign) {
1739
QQuickText::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
1742
emit q->horizontalAlignmentChanged(hAlign);
1743
if (oldEffectiveHAlign != q->effectiveHAlign())
1744
emit q->effectiveHorizontalAlignmentChanged();
1750
bool QQuickTextPrivate::determineHorizontalAlignment()
1752
if (hAlignImplicit) {
1754
bool alignToRight = text.isEmpty() ? qApp->inputMethod()->inputDirection() == Qt::RightToLeft : rightToLeftText;
1756
bool alignToRight = rightToLeftText;
1758
return setHAlign(alignToRight ? QQuickText::AlignRight : QQuickText::AlignLeft);
1763
void QQuickTextPrivate::mirrorChange()
1766
if (q->isComponentComplete()) {
1767
if (!hAlignImplicit && (hAlign == QQuickText::AlignRight || hAlign == QQuickText::AlignLeft)) {
1769
emit q->effectiveHorizontalAlignmentChanged();
1774
QQuickText::VAlignment QQuickText::vAlign() const
1776
Q_D(const QQuickText);
1780
void QQuickText::setVAlign(VAlignment align)
1783
if (d->vAlign == align)
1787
emit verticalAlignmentChanged(align);
1791
\qmlproperty enumeration QtQuick2::Text::wrapMode
1793
Set this property to wrap the text to the Text item's width. The text will only
1794
wrap if an explicit width has been set. wrapMode can be one of:
1797
\li Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l contentWidth will exceed a set width.
1798
\li Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l contentWidth will exceed a set width.
1799
\li Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
1800
\li 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.
1803
QQuickText::WrapMode QQuickText::wrapMode() const
1805
Q_D(const QQuickText);
1809
void QQuickText::setWrapMode(WrapMode mode)
1812
if (mode == d->wrapMode)
1818
emit wrapModeChanged();
1822
\qmlproperty int QtQuick2::Text::lineCount
1824
Returns the number of lines visible in the text item.
1826
This property is not supported for rich text.
1828
\sa maximumLineCount
1830
int QQuickText::lineCount() const
1832
Q_D(const QQuickText);
1833
return d->lineCount;
1837
\qmlproperty bool QtQuick2::Text::truncated
1839
Returns true if the text has been truncated due to \l maximumLineCount
1842
This property is not supported for rich text.
1844
\sa maximumLineCount, elide
1846
bool QQuickText::truncated() const
1848
Q_D(const QQuickText);
1849
return d->truncated;
1853
\qmlproperty int QtQuick2::Text::maximumLineCount
1855
Set this property to limit the number of lines that the text item will show.
1856
If elide is set to Text.ElideRight, the text will be elided appropriately.
1857
By default, this is the value of the largest possible integer.
1859
This property is not supported for rich text.
1861
\sa lineCount, elide
1863
int QQuickText::maximumLineCount() const
1865
Q_D(const QQuickText);
1866
return d->maximumLineCount();
1869
void QQuickText::setMaximumLineCount(int lines)
1873
d->maximumLineCountValid = lines==INT_MAX ? false : true;
1874
if (d->maximumLineCount() != lines) {
1875
d->extra.value().maximumLineCount = lines;
1876
d->implicitHeightValid = false;
1878
emit maximumLineCountChanged();
1882
void QQuickText::resetMaximumLineCount()
1885
setMaximumLineCount(INT_MAX);
1886
if (d->truncated != false) {
1887
d->truncated = false;
1888
emit truncatedChanged();
1893
\qmlproperty enumeration QtQuick2::Text::textFormat
1895
The way the text property should be displayed.
1897
Supported text formats are:
1900
\li Text.AutoText (default)
1906
If the text format is \c Text.AutoText the Text item
1907
will automatically determine whether the text should be treated as
1908
styled text. This determination is made using Qt::mightBeRichText()
1909
which uses a fast and therefore simple heuristic. It mainly checks
1910
whether there is something that looks like a tag before the first
1911
line break. Although the result may be correct for common cases,
1912
there is no guarantee.
1914
Text.StyledText is an optimized format supporting some basic text
1915
styling markup, in the style of HTML 3.2:
1919
<strong></strong> - bold
1923
<u> - underlined text
1924
<font color="color_name" size="1-7"></font>
1925
<h1> to <h6> - headers
1926
<a href=""> - anchor
1927
<img src="" align="top,middle,bottom" width="" height=""> - inline images
1928
<ol type="">, <ul type=""> and <li> - ordered and unordered lists
1929
<pre></pre> - preformatted
1933
\c Text.StyledText parser is strict, requiring tags to be correctly nested.
1942
text: "<b>Hello</b> <i>World!</i>"
1946
textFormat: Text.RichText
1947
text: "<b>Hello</b> <i>World!</i>"
1951
textFormat: Text.PlainText
1952
text: "<b>Hello</b> <i>World!</i>"
1956
\li \image declarative-textformat.png
1959
Text.RichText supports a larger subset of HTML 4, as described on the
1960
\l {Supported HTML Subset} page. You should prefer using Text.PlainText
1961
or Text.StyledText instead, as they offer better performance.
1963
QQuickText::TextFormat QQuickText::textFormat() const
1965
Q_D(const QQuickText);
1969
void QQuickText::setTextFormat(TextFormat format)
1972
if (format == d->format)
1975
bool wasRich = d->richText;
1976
d->richText = format == RichText;
1977
d->styledText = format == StyledText || (format == AutoText && Qt::mightBeRichText(d->text));
1979
if (isComponentComplete()) {
1980
if (!wasRich && d->richText) {
1982
d->extra->doc->setText(d->text);
1983
d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
1985
d->rightToLeftText = d->text.isRightToLeft();
1987
d->determineHorizontalAlignment();
1991
emit textFormatChanged(d->format);
1995
\qmlproperty enumeration QtQuick2::Text::elide
1997
Set this property to elide parts of the text fit to the Text item's width.
1998
The text will only elide if an explicit width has been set.
2000
This property cannot be used with rich text.
2004
\li Text.ElideNone - the default
2006
\li Text.ElideMiddle
2010
If this property is set to Text.ElideRight, it can be used with \l {wrapMode}{wrapped}
2011
text. The text will only elide if \c maximumLineCount, or \c height has been set.
2012
If both \c maximumLineCount and \c height are set, \c maximumLineCount will
2013
apply unless the lines do not fit in the height allowed.
2015
If the text is a multi-length string, and the mode is not \c Text.ElideNone,
2016
the first string that fits will be used, otherwise the last will be elided.
2018
Multi-length strings are ordered from longest to shortest, separated by the
2019
Unicode "String Terminator" character \c U009C (write this in QML with \c{"\u009C"} or \c{"\x9C"}).
2021
QQuickText::TextElideMode QQuickText::elideMode() const
2023
Q_D(const QQuickText);
2024
return d->elideMode;
2027
void QQuickText::setElideMode(QQuickText::TextElideMode mode)
2030
if (mode == d->elideMode)
2033
d->elideMode = mode;
2036
emit elideModeChanged(mode);
2040
\qmlproperty url QtQuick2::Text::baseUrl
2042
This property specifies a base URL which is used to resolve relative URLs
2045
Urls are resolved to be within the same directory as the target of the base
2046
URL meaning any portion of the path after the last '/' will be ignored.
2049
\header \li Base URL \li Relative URL \li Resolved URL
2050
\row \li http://qt-project.org/ \li images/logo.png \li http://qt-project.org/images/logo.png
2051
\row \li http://qt-project.org/index.html \li images/logo.png \li http://qt-project.org/images/logo.png
2052
\row \li http://qt-project.org/content \li images/logo.png \li http://qt-project.org/content/images/logo.png
2053
\row \li http://qt-project.org/content/ \li images/logo.png \li http://qt-project.org/content/images/logo.png
2054
\row \li http://qt-project.org/content/index.html \li images/logo.png \li http://qt-project.org/content/images/logo.png
2055
\row \li http://qt-project.org/content/index.html \li ../images/logo.png \li http://qt-project.org/images/logo.png
2056
\row \li http://qt-project.org/content/index.html \li /images/logo.png \li http://qt-project.org/images/logo.png
2059
The default value is the url of the QML file instantiating the Text item.
2062
QUrl QQuickText::baseUrl() const
2064
Q_D(const QQuickText);
2065
if (d->baseUrl.isEmpty()) {
2066
if (QQmlContext *context = qmlContext(this))
2067
const_cast<QQuickTextPrivate *>(d)->baseUrl = context->baseUrl();
2072
void QQuickText::setBaseUrl(const QUrl &url)
2075
if (baseUrl() != url) {
2080
d->extra->doc->setBaseUrl(url);
2082
if (d->styledText) {
2083
d->textHasChanged = true;
2084
qDeleteAll(d->imgTags);
2088
emit baseUrlChanged();
2092
void QQuickText::resetBaseUrl()
2094
if (QQmlContext *context = qmlContext(this))
2095
setBaseUrl(context->baseUrl());
2101
QRectF QQuickText::boundingRect() const
2103
Q_D(const QQuickText);
2105
QRectF rect = d->layedOutTextRect;
2106
rect.moveLeft(QQuickTextUtil::alignedX(rect.width(), width(), d->hAlign));
2107
rect.moveTop(QQuickTextUtil::alignedY(rect.height(), height(), d->vAlign));
2109
if (d->style != Normal)
2110
rect.adjust(-1, 0, 1, 2);
2111
// Could include font max left/right bearings to either side of rectangle.
2116
QRectF QQuickText::clipRect() const
2118
Q_D(const QQuickText);
2120
QRectF rect = QQuickImplicitSizeItem::clipRect();
2121
if (d->style != Normal)
2122
rect.adjust(-1, 0, 1, 2);
2127
void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
2130
if (d->text.isEmpty()) {
2131
QQuickItem::geometryChanged(newGeometry, oldGeometry);
2135
bool widthChanged = newGeometry.width() != oldGeometry.width();
2136
bool heightChanged = newGeometry.height() != oldGeometry.height();
2137
bool wrapped = d->wrapMode != QQuickText::NoWrap;
2138
bool elide = d->elideMode != QQuickText::ElideNone;
2139
bool scaleFont = d->fontSizeMode() != QQuickText::FixedSize && (widthValid() || heightValid());
2140
bool verticalScale = (d->fontSizeMode() & QQuickText::VerticalFit) && heightValid();
2142
bool widthMaximum = newGeometry.width() >= oldGeometry.width() && !d->widthExceeded;
2143
bool heightMaximum = newGeometry.height() >= oldGeometry.height() && !d->heightExceeded;
2145
if ((!widthChanged && !heightChanged) || d->internalWidthUpdate)
2146
goto geomChangeDone;
2148
if (effectiveHAlign() != QQuickText::AlignLeft && widthChanged) {
2149
// If the width has changed and we're not left aligned do an update so the text is
2150
// repositioned even if a full layout isn't required.
2151
d->updateType = QQuickTextPrivate::UpdatePaintNode;
2155
if (!wrapped && !elide && !scaleFont)
2156
goto geomChangeDone; // left aligned unwrapped text without eliding never needs relayout
2158
if (elide // eliding and dimensions were and remain invalid;
2159
&& ((widthValid() && oldGeometry.width() <= 0 && newGeometry.width() <= 0)
2160
|| (heightValid() && oldGeometry.height() <= 0 && newGeometry.height() <= 0))) {
2161
goto geomChangeDone;
2164
if (widthMaximum && heightMaximum && !d->isLineLaidOutConnected()) // Size is sufficient and growing.
2165
goto geomChangeDone;
2167
if (!(widthChanged || widthMaximum) && !d->isLineLaidOutConnected()) { // only height has changed
2168
if (newGeometry.height() > oldGeometry.height()) {
2169
if (!d->heightExceeded) // Height is adequate and growing.
2170
goto geomChangeDone;
2171
if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing.
2172
goto geomChangeDone;
2173
} else if (newGeometry.height() < oldGeometry.height()) {
2174
if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height.
2175
goto geomChangeDone;
2177
if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count.
2178
&& d->elideMode != QQuickText::ElideRight
2179
&& !(d->maximumLineCountValid && d->widthExceeded)) {
2180
goto geomChangeDone;
2183
} else if (!heightChanged && widthMaximum) {
2184
goto geomChangeDone;
2187
if (d->updateOnComponentComplete || d->textHasChanged) {
2188
// We need to re-elide
2191
// We just need to re-layout
2196
QQuickItem::geometryChanged(newGeometry, oldGeometry);
2199
void QQuickText::triggerPreprocess()
2202
if (d->updateType == QQuickTextPrivate::UpdateNone)
2203
d->updateType = QQuickTextPrivate::UpdatePreprocess;
2207
QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
2212
if (d->text.isEmpty()) {
2217
if (d->updateType != QQuickTextPrivate::UpdatePaintNode && oldNode != 0) {
2218
// Update done in preprocess() in the nodes
2219
d->updateType = QQuickTextPrivate::UpdateNone;
2223
d->updateType = QQuickTextPrivate::UpdateNone;
2225
const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height(), height(), d->vAlign);
2227
QQuickTextNode *node = 0;
2229
node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
2231
node = static_cast<QQuickTextNode *>(oldNode);
2234
node->setUseNativeRenderer(d->renderType == NativeRendering);
2235
node->deleteContent();
2236
node->setMatrix(QMatrix4x4());
2238
const QColor color = QColor::fromRgba(d->color);
2239
const QColor styleColor = QColor::fromRgba(d->styleColor);
2240
const QColor linkColor = QColor::fromRgba(d->linkColor);
2243
const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), width(), d->hAlign);
2245
node->addTextDocument(QPointF(dx, dy), d->extra->doc, color, d->style, styleColor, linkColor);
2246
} else if (d->layedOutTextRect.width() > 0) {
2247
const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, width(), d->hAlign);
2248
int unelidedLineCount = d->lineCount;
2250
unelidedLineCount -= 1;
2251
if (unelidedLineCount > 0) {
2252
node->addTextLayout(
2255
color, d->style, styleColor, linkColor,
2256
QColor(), QColor(), -1, -1,
2257
0, unelidedLineCount);
2260
node->addTextLayout(QPointF(dx, dy), d->elideLayout, color, d->style, styleColor, linkColor);
2262
foreach (QQuickStyledTextImgTag *img, d->visibleImgTags) {
2263
QQuickPixmap *pix = img->pix;
2264
if (pix && pix->isReady())
2265
node->addImage(QRectF(img->pos.x() + dx, img->pos.y() + dy, pix->width(), pix->height()), pix->image());
2271
void QQuickText::updatePolish()
2278
\qmlproperty real QtQuick2::Text::contentWidth
2280
Returns the width of the text, including width past the width
2281
which is covered due to insufficient wrapping if WrapMode is set.
2283
qreal QQuickText::contentWidth() const
2285
Q_D(const QQuickText);
2286
return d->layedOutTextRect.width();
2290
\qmlproperty real QtQuick2::Text::contentHeight
2292
Returns the height of the text, including height past the height
2293
which is covered due to there being more text than fits in the set height.
2295
qreal QQuickText::contentHeight() const
2297
Q_D(const QQuickText);
2298
return d->layedOutTextRect.height();
2302
\qmlproperty real QtQuick2::Text::lineHeight
2304
Sets the line height for the text.
2305
The value can be in pixels or a multiplier depending on lineHeightMode.
2307
The default value is a multiplier of 1.0.
2308
The line height must be a positive value.
2310
qreal QQuickText::lineHeight() const
2312
Q_D(const QQuickText);
2313
return d->lineHeight();
2316
void QQuickText::setLineHeight(qreal lineHeight)
2320
if ((d->lineHeight() == lineHeight) || (lineHeight < 0.0))
2323
d->extra.value().lineHeight = lineHeight;
2324
d->implicitHeightValid = false;
2326
emit lineHeightChanged(lineHeight);
2330
\qmlproperty enumeration QtQuick2::Text::lineHeightMode
2332
This property determines how the line height is specified.
2333
The possible values are:
2336
\li Text.ProportionalHeight (default) - this sets the spacing proportional to the
2337
line (as a multiplier). For example, set to 2 for double spacing.
2338
\li Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
2341
QQuickText::LineHeightMode QQuickText::lineHeightMode() const
2343
Q_D(const QQuickText);
2344
return d->lineHeightMode();
2347
void QQuickText::setLineHeightMode(LineHeightMode mode)
2350
if (mode == d->lineHeightMode())
2353
d->implicitHeightValid = false;
2354
d->extra.value().lineHeightMode = mode;
2357
emit lineHeightModeChanged(mode);
2361
\qmlproperty enumeration QtQuick2::Text::fontSizeMode
2363
This property specifies how the font size of the displayed text is determined.
2364
The possible values are:
2367
\li Text.FixedSize (default) - The size specified by \l font.pixelSize
2368
or \l font.pointSize is used.
2369
\li Text.HorizontalFit - The largest size up to the size specified that fits
2370
within the width of the item without wrapping is used.
2371
\li Text.VerticalFit - The largest size up to the size specified that fits
2372
the height of the item is used.
2373
\li Text.Fit - The largest size up to the size specified the fits within the
2374
width and height of the item is used.
2377
The font size of fitted text has a minimum bound specified by the
2378
minimumPointSize or minimumPixelSize property and maximum bound specified
2379
by either the \l font.pointSize or \l font.pixelSize properties.
2381
If the text does not fit within the item bounds with the minimum font size
2382
the text will be elided as per the \l elide property.
2385
QQuickText::FontSizeMode QQuickText::fontSizeMode() const
2387
Q_D(const QQuickText);
2388
return d->fontSizeMode();
2391
void QQuickText::setFontSizeMode(FontSizeMode mode)
2394
if (d->fontSizeMode() == mode)
2399
d->extra.value().fontSizeMode = mode;
2400
emit fontSizeModeChanged();
2404
\qmlproperty int QtQuick2::Text::minimumPixelSize
2406
This property specifies the minimum font pixel size of text scaled by the
2407
fontSizeMode property.
2409
If the fontSizeMode is Text.FixedSize or the \l font.pixelSize is -1 this
2410
property is ignored.
2413
int QQuickText::minimumPixelSize() const
2415
Q_D(const QQuickText);
2416
return d->minimumPixelSize();
2419
void QQuickText::setMinimumPixelSize(int size)
2422
if (d->minimumPixelSize() == size)
2425
if (d->fontSizeMode() != FixedSize && (widthValid() || heightValid()))
2427
d->extra.value().minimumPixelSize = size;
2428
emit minimumPixelSizeChanged();
2432
\qmlproperty int QtQuick2::Text::minimumPointSize
2434
This property specifies the minimum font point \l size of text scaled by
2435
the fontSizeMode property.
2437
If the fontSizeMode is Text.FixedSize or the \l font.pointSize is -1 this
2438
property is ignored.
2441
int QQuickText::minimumPointSize() const
2443
Q_D(const QQuickText);
2444
return d->minimumPointSize();
2447
void QQuickText::setMinimumPointSize(int size)
2450
if (d->minimumPointSize() == size)
2453
if (d->fontSizeMode() != FixedSize && (widthValid() || heightValid()))
2455
d->extra.value().minimumPointSize = size;
2456
emit minimumPointSizeChanged();
2460
Returns the number of resources (images) that are being loaded asynchronously.
2462
int QQuickText::resourcesLoading() const
2464
Q_D(const QQuickText);
2465
if (d->richText && d->extra.isAllocated() && d->extra->doc)
2466
return d->extra->doc->resourcesLoading();
2471
void QQuickText::componentComplete()
2474
if (d->updateOnComponentComplete) {
2477
d->extra->doc->setText(d->text);
2478
d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
2480
d->rightToLeftText = d->text.isRightToLeft();
2482
d->determineHorizontalAlignment();
2484
QQuickItem::componentComplete();
2485
if (d->updateOnComponentComplete)
2489
QString QQuickTextPrivate::anchorAt(const QTextLayout *layout, const QPointF &mousePos)
2491
for (int i = 0; i < layout->lineCount(); ++i) {
2492
QTextLine line = layout->lineAt(i);
2493
if (line.naturalTextRect().contains(mousePos)) {
2494
int charPos = line.xToCursor(mousePos.x(), QTextLine::CursorOnCharacter);
2495
foreach (const QTextLayout::FormatRange &formatRange, layout->additionalFormats()) {
2496
if (formatRange.format.isAnchor()
2497
&& charPos >= formatRange.start
2498
&& charPos < formatRange.start + formatRange.length) {
2499
return formatRange.format.anchorHref();
2508
QString QQuickTextPrivate::anchorAt(const QPointF &mousePos) const
2510
Q_Q(const QQuickText);
2511
QPointF translatedMousePos = mousePos;
2512
translatedMousePos.ry() -= QQuickTextUtil::alignedY(layedOutTextRect.height(), q->height(), vAlign);
2514
QString link = anchorAt(&layout, translatedMousePos);
2515
if (link.isEmpty() && elideLayout)
2516
link = anchorAt(elideLayout, translatedMousePos);
2518
} else if (richText && extra.isAllocated() && extra->doc) {
2519
translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), q->width(), hAlign);
2520
return extra->doc->documentLayout()->anchorAt(translatedMousePos);
2525
bool QQuickTextPrivate::isLinkActivatedConnected()
2528
IS_SIGNAL_CONNECTED(q, QQuickText, linkActivated, (const QString &));
2532
void QQuickText::mousePressEvent(QMouseEvent *event)
2537
if (d->isLinkActivatedConnected())
2538
link = d->anchorAt(event->localPos());
2540
if (link.isEmpty()) {
2541
event->setAccepted(false);
2543
d->extra.value().activeLink = link;
2546
// ### may malfunction if two of the same links are clicked & dragged onto each other)
2548
if (!event->isAccepted())
2549
QQuickItem::mousePressEvent(event);
2554
void QQuickText::mouseReleaseEvent(QMouseEvent *event)
2558
// ### confirm the link, and send a signal out
2561
if (d->isLinkActivatedConnected())
2562
link = d->anchorAt(event->localPos());
2564
if (!link.isEmpty() && d->extra.isAllocated() && d->extra->activeLink == link)
2565
emit linkActivated(d->extra->activeLink);
2567
event->setAccepted(false);
2569
if (!event->isAccepted())
2570
QQuickItem::mouseReleaseEvent(event);