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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "private/qdeclarativetext_p.h"
43 #include "private/qdeclarativetext_p_p.h"
44 #include <qdeclarativestyledtext_p.h>
45 #include <qdeclarativeinfo.h>
46 #include <qdeclarativepixmapcache_p.h>
49 #include <QTextLayout>
51 #include <QTextDocument>
52 #include <QGraphicsSceneMouseEvent>
54 #include <QAbstractTextDocumentLayout>
60 extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
62 class QTextDocumentWithImageResources : public QTextDocument {
66 QTextDocumentWithImageResources(QDeclarativeText *parent);
67 virtual ~QTextDocumentWithImageResources();
69 void setText(const QString &);
70 int resourcesLoading() const { return outstanding; }
73 QVariant loadResource(int type, const QUrl &name);
76 void requestFinished();
79 QHash<QUrl, QDeclarativePixmap *> m_resources;
82 static QSet<QUrl> errors;
85 DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE);
87 QString QDeclarativeTextPrivate::elideChar = QString(0x2026);
89 QDeclarativeTextPrivate::QDeclarativeTextPrivate()
90 : color((QRgb)0), style(QDeclarativeText::Normal), hAlign(QDeclarativeText::AlignLeft),
91 vAlign(QDeclarativeText::AlignTop), elideMode(QDeclarativeText::ElideNone),
92 format(QDeclarativeText::AutoText), wrapMode(QDeclarativeText::NoWrap), lineHeight(1),
93 lineHeightMode(QDeclarativeText::ProportionalHeight), lineCount(1), truncated(false), maximumLineCount(INT_MAX),
94 maximumLineCountValid(false), imageCacheDirty(true), updateOnComponentComplete(true), richText(false), singleline(false),
95 cacheAllTextAsImage(true), internalWidthUpdate(false), requireImplicitWidth(false), hAlignImplicit(true),
96 rightToLeftText(false), layoutTextElided(false), naturalWidth(0), doc(0)
98 cacheAllTextAsImage = enableImageCache();
99 QGraphicsItemPrivate::acceptedMouseButtons = Qt::LeftButton;
100 QGraphicsItemPrivate::flags = QGraphicsItemPrivate::flags & ~QGraphicsItem::ItemHasNoContents;
103 QTextDocumentWithImageResources::QTextDocumentWithImageResources(QDeclarativeText *parent)
104 : QTextDocument(parent), outstanding(0)
108 QTextDocumentWithImageResources::~QTextDocumentWithImageResources()
110 if (!m_resources.isEmpty())
111 qDeleteAll(m_resources);
114 QVariant QTextDocumentWithImageResources::loadResource(int type, const QUrl &name)
116 QDeclarativeContext *context = qmlContext(parent());
117 QUrl url = context->resolvedUrl(name);
119 if (type == QTextDocument::ImageResource) {
120 QHash<QUrl, QDeclarativePixmap *>::Iterator iter = m_resources.find(url);
122 if (iter == m_resources.end()) {
123 QDeclarativePixmap *p = new QDeclarativePixmap(context->engine(), url);
124 iter = m_resources.insert(name, p);
126 if (p->isLoading()) {
127 p->connectFinished(this, SLOT(requestFinished()));
132 QDeclarativePixmap *p = *iter;
135 } else if (p->isError()) {
136 if (!errors.contains(url)) {
138 qmlInfo(parent()) << p->error();
143 return QTextDocument::loadResource(type,url); // The *resolved* URL
146 void QTextDocumentWithImageResources::requestFinished()
149 if (outstanding == 0) {
150 QDeclarativeText *textItem = static_cast<QDeclarativeText*>(parent());
151 QString text = textItem->text();
152 #ifndef QT_NO_TEXTHTMLPARSER
157 QDeclarativeTextPrivate *d = QDeclarativeTextPrivate::get(textItem);
162 void QTextDocumentWithImageResources::setText(const QString &text)
164 if (!m_resources.isEmpty()) {
165 qDeleteAll(m_resources);
170 #ifndef QT_NO_TEXTHTMLPARSER
177 QSet<QUrl> QTextDocumentWithImageResources::errors;
179 QDeclarativeTextPrivate::~QDeclarativeTextPrivate()
183 qreal QDeclarativeTextPrivate::implicitWidth() const
185 if (!requireImplicitWidth) {
186 // We don't calculate implicitWidth unless it is required.
187 // We need to force a size update now to ensure implicitWidth is calculated
188 QDeclarativeTextPrivate *me = const_cast<QDeclarativeTextPrivate*>(this);
189 me->requireImplicitWidth = true;
192 return mImplicitWidth;
195 void QDeclarativeTextPrivate::updateLayout()
197 Q_Q(QDeclarativeText);
198 if (!q->isComponentComplete()) {
199 updateOnComponentComplete = true;
203 layoutTextElided = false;
204 // Setup instance of QTextLayout for all cases other than richtext
206 layout.clearLayout();
207 layout.setFont(font);
208 if (format != QDeclarativeText::StyledText) {
210 tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
211 singleline = !tmp.contains(QChar::LineSeparator);
212 if (singleline && !maximumLineCountValid && elideMode != QDeclarativeText::ElideNone && q->widthValid()) {
213 QFontMetrics fm(font);
214 tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width());
216 layoutTextElided = true;
219 emit q->truncatedChanged();
226 QDeclarativeStyledText::parse(text, layout);
233 void QDeclarativeTextPrivate::updateSize()
235 Q_Q(QDeclarativeText);
237 if (!q->isComponentComplete()) {
238 updateOnComponentComplete = true;
242 if (!requireImplicitWidth) {
243 emit q->implicitWidthChanged();
244 // if the implicitWidth is used, then updateSize() has already been called (recursively)
245 if (requireImplicitWidth)
249 invalidateImageCache();
251 QFontMetrics fm(font);
252 if (text.isEmpty()) {
253 q->setImplicitWidth(0);
254 q->setImplicitHeight(fm.height());
255 paintedSize = QSize(0, fm.height());
256 emit q->paintedSizeChanged();
261 int dy = q->height();
264 //setup instance of QTextLayout for all cases other than richtext
266 QRect textRect = setupTextLayout();
267 if (layedOutTextRect.size() != textRect.size())
268 q->prepareGeometryChange();
269 layedOutTextRect = textRect;
270 size = textRect.size();
273 singleline = false; // richtext can't elide or be optimized for single-line case
275 doc->setDefaultFont(font);
277 QDeclarativeText::HAlignment horizontalAlignment = q->effectiveHAlign();
278 if (rightToLeftText) {
279 if (horizontalAlignment == QDeclarativeText::AlignLeft)
280 horizontalAlignment = QDeclarativeText::AlignRight;
281 else if (horizontalAlignment == QDeclarativeText::AlignRight)
282 horizontalAlignment = QDeclarativeText::AlignLeft;
285 option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
286 option.setWrapMode(QTextOption::WrapMode(wrapMode));
287 doc->setDefaultTextOption(option);
288 if (requireImplicitWidth && q->widthValid()) {
289 doc->setTextWidth(-1);
290 naturalWidth = doc->idealWidth();
292 if (wrapMode != QDeclarativeText::NoWrap && q->widthValid())
293 doc->setTextWidth(q->width());
295 doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
296 dy -= (int)doc->size().height();
297 QSize dsize = doc->size().toSize();
298 if (dsize != layedOutTextRect.size()) {
299 q->prepareGeometryChange();
300 layedOutTextRect = QRect(QPoint(0,0), dsize);
302 size = QSize(int(doc->idealWidth()),dsize.height());
306 if (q->heightValid()) {
307 if (vAlign == QDeclarativeText::AlignBottom)
309 else if (vAlign == QDeclarativeText::AlignVCenter)
312 q->setBaselineOffset(fm.ascent() + yoff);
314 //### need to comfirm cost of always setting these for richText
315 internalWidthUpdate = true;
316 if (!q->widthValid())
317 q->setImplicitWidth(size.width());
318 else if (requireImplicitWidth)
319 q->setImplicitWidth(naturalWidth);
320 internalWidthUpdate = false;
321 q->setImplicitHeight(size.height());
322 if (paintedSize != size) {
324 emit q->paintedSizeChanged();
330 Lays out the QDeclarativeTextPrivate::layout QTextLayout in the constraints of the QDeclarativeText.
332 Returns the size of the final text. This can be used to position the text vertically (the text is
333 already absolutely positioned horizontally).
335 QRect QDeclarativeTextPrivate::setupTextLayout()
337 // ### text layout handling should be profiled and optimized as needed
338 // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
339 Q_Q(QDeclarativeText);
340 layout.setCacheEnabled(true);
343 int visibleCount = 0;
347 lineWidth = q->width();
349 QTextOption textOption = layout.textOption();
350 textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
351 textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
352 layout.setTextOption(textOption);
354 bool elideText = false;
355 bool truncate = false;
357 QFontMetrics fm(layout.font());
358 elidePos = QPointF();
360 if (requireImplicitWidth && q->widthValid()) {
361 // requires an extra layout
363 if (layoutTextElided) {
364 // We have provided elided text to the layout, but we must calculate unelided width.
365 elidedText = layout.text();
366 layout.setText(text);
368 layout.beginLayout();
370 QTextLine line = layout.createLine();
376 for (int i = 0; i < layout.lineCount(); ++i) {
377 QTextLine line = layout.lineAt(i);
378 br = br.united(line.naturalTextRect());
380 naturalWidth = br.width();
381 if (layoutTextElided)
382 layout.setText(elidedText);
385 if (maximumLineCountValid) {
386 layout.beginLayout();
389 int linesLeft = maximumLineCount;
390 int visibleTextLength = 0;
391 while (linesLeft > 0) {
392 QTextLine line = layout.createLine();
398 line.setLineWidth(lineWidth);
399 visibleTextLength += line.textLength();
401 if (--linesLeft == 0) {
402 if (visibleTextLength < text.length()) {
404 if (elideMode==QDeclarativeText::ElideRight && q->widthValid()) {
405 qreal elideWidth = fm.width(elideChar);
406 // Need to correct for alignment
407 line.setLineWidth(lineWidth-elideWidth);
408 if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) {
409 line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y()));
410 elidePos.setX(line.naturalTextRect().left() - elideWidth);
412 elidePos.setX(line.naturalTextRect().right());
422 if (truncated != truncate) {
423 truncated = truncate;
424 emit q->truncatedChanged();
427 layout.beginLayout();
429 QTextLine line = layout.createLine();
434 line.setLineWidth(lineWidth);
441 for (int i = 0; i < layout.lineCount(); ++i) {
442 QTextLine line = layout.lineAt(i);
444 line.setPosition(QPointF(line.position().x(), height));
445 if (elideText && i == layout.lineCount()-1) {
446 elidePos.setY(height + fm.ascent());
447 br = br.united(QRectF(elidePos, QSizeF(fm.width(elideChar), fm.ascent())));
449 br = br.united(line.naturalTextRect());
450 height += (lineHeightMode == QDeclarativeText::FixedHeight) ? lineHeight : line.height() * lineHeight;
452 br.setHeight(height);
454 if (!q->widthValid())
455 naturalWidth = br.width();
457 //Update the number of visible lines
458 if (lineCount != visibleCount) {
459 lineCount = visibleCount;
460 emit q->lineCountChanged();
463 return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height()));
467 Returns a painted version of the QDeclarativeTextPrivate::layout QTextLayout.
468 If \a drawStyle is true, the style color overrides all colors in the document.
470 QPixmap QDeclarativeTextPrivate::textLayoutImage(bool drawStyle)
473 QSize size = layedOutTextRect.size();
476 if (!size.isEmpty()) {
477 img.fill(Qt::transparent);
479 bool oldSmooth = qt_applefontsmoothing_enabled;
480 qt_applefontsmoothing_enabled = false;
484 qt_applefontsmoothing_enabled = oldSmooth;
486 drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle);
492 Paints the QDeclarativeTextPrivate::layout QTextLayout into \a painter at \a pos. If
493 \a drawStyle is true, the style color overrides all colors in the document.
495 void QDeclarativeTextPrivate::drawTextLayout(QPainter *painter, const QPointF &pos, bool drawStyle)
498 painter->setPen(styleColor);
500 painter->setPen(color);
501 painter->setFont(font);
502 layout.draw(painter, pos);
503 if (!elidePos.isNull())
504 painter->drawText(pos + elidePos, elideChar);
508 Returns a painted version of the QDeclarativeTextPrivate::doc QTextDocument.
509 If \a drawStyle is true, the style color overrides all colors in the document.
511 QPixmap QDeclarativeTextPrivate::textDocumentImage(bool drawStyle)
513 QSize size = doc->size().toSize();
517 img.fill(Qt::transparent);
519 bool oldSmooth = qt_applefontsmoothing_enabled;
520 qt_applefontsmoothing_enabled = false;
524 qt_applefontsmoothing_enabled = oldSmooth;
527 QAbstractTextDocumentLayout::PaintContext context;
529 QTextOption oldOption(doc->defaultTextOption());
531 context.palette.setColor(QPalette::Text, styleColor);
532 QTextOption colorOption(doc->defaultTextOption());
533 colorOption.setFlags(QTextOption::SuppressColors);
534 doc->setDefaultTextOption(colorOption);
536 context.palette.setColor(QPalette::Text, color);
538 doc->documentLayout()->draw(&p, context);
540 doc->setDefaultTextOption(oldOption);
545 Mark the image cache as dirty.
547 void QDeclarativeTextPrivate::invalidateImageCache()
549 Q_Q(QDeclarativeText);
551 if(cacheAllTextAsImage || style != QDeclarativeText::Normal){//If actually using the image cache
555 imageCacheDirty = true;
556 imageCache = QPixmap();
558 if (q->isComponentComplete())
563 Tests if the image cache is dirty, and repaints it if it is.
565 void QDeclarativeTextPrivate::checkImageCache()
567 if (!imageCacheDirty)
570 if (text.isEmpty()) {
572 imageCache = QPixmap();
580 textImage = textDocumentImage(false);
581 if (style != QDeclarativeText::Normal)
582 styledImage = textDocumentImage(true); //### should use styleColor
584 textImage = textLayoutImage(false);
585 if (style != QDeclarativeText::Normal)
586 styledImage = textLayoutImage(true); //### should use styleColor
590 case QDeclarativeText::Outline:
591 imageCache = drawOutline(textImage, styledImage);
593 case QDeclarativeText::Sunken:
594 imageCache = drawOutline(textImage, styledImage, -1);
596 case QDeclarativeText::Raised:
597 imageCache = drawOutline(textImage, styledImage, 1);
600 imageCache = textImage;
606 imageCacheDirty = false;
610 Ensures the QDeclarativeTextPrivate::doc variable is set to a valid text document
612 void QDeclarativeTextPrivate::ensureDoc()
615 Q_Q(QDeclarativeText);
616 doc = new QTextDocumentWithImageResources(q);
617 doc->setDocumentMargin(0);
622 Draw \a styleSource as an outline around \a source and return the new image.
624 QPixmap QDeclarativeTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource)
626 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
627 img.fill(Qt::transparent);
632 pos += QPoint(-1, 0);
633 ppm.drawPixmap(pos, styleSource);
635 ppm.drawPixmap(pos, styleSource);
636 pos += QPoint(-1, -1);
637 ppm.drawPixmap(pos, styleSource);
639 ppm.drawPixmap(pos, styleSource);
641 pos += QPoint(0, -1);
642 ppm.drawPixmap(pos, source);
649 Draw \a styleSource below \a source at \a yOffset and return the new image.
651 QPixmap QDeclarativeTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset)
653 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
654 img.fill(Qt::transparent);
658 ppm.drawPixmap(QPoint(0, yOffset), styleSource);
659 ppm.drawPixmap(0, 0, source);
667 \qmlclass Text QDeclarativeText
668 \ingroup qml-basic-visual-elements
670 \brief The Text item allows you to add formatted text to a scene.
673 Text items can display both plain and rich text. For example, red text with
674 a specific font and size can be defined like this:
679 font.family: "Helvetica"
685 Rich text is defined using HTML-style markup:
689 text: "<b>Hello</b> <i>World!</i>"
693 \image declarative-text.png
695 If height and width are not explicitly set, Text will attempt to determine how
696 much room is needed and set it accordingly. Unless \l wrapMode is set, it will always
697 prefer width to height (all text will be placed on a single line).
699 The \l elide property can alternatively be used to fit a single line of
700 plain text to a set width.
702 Note that the \l{Supported HTML Subset} is limited. Also, if the text contains
703 HTML img tags that load remote images, the text is reloaded.
705 Text provides read-only text. For editable text, see \l TextEdit.
707 \sa {declarative/text/fonts}{Fonts example}
709 QDeclarativeText::QDeclarativeText(QDeclarativeItem *parent)
710 : QDeclarativeImplicitSizeItem(*(new QDeclarativeTextPrivate), parent)
714 QDeclarativeText::~QDeclarativeText()
719 \qmlproperty bool Text::clip
720 This property holds whether the text is clipped.
722 Note that if the text does not fit in the bounding rectangle it will be abruptly chopped.
724 If you want to display potentially long text in a limited space, you probably want to use \c elide instead.
728 \qmlproperty bool Text::smooth
730 This property holds whether the text is smoothly scaled or transformed.
732 Smooth filtering gives better visual quality, but is slower. If
733 the item is displayed at its natural size, this property has no visual or
736 \note Generally scaling artifacts are only visible if the item is stationary on
737 the screen. A common pattern when animating an item is to disable smooth
738 filtering at the beginning of the animation and reenable it at the conclusion.
742 \qmlsignal Text::onLinkActivated(string link)
744 This handler is called when the user clicks on a link embedded in the text.
745 The link must be in rich text or HTML format and the
746 \a link string provides access to the particular link.
748 \snippet doc/src/snippets/declarative/text/onLinkActivated.qml 0
750 The example code will display the text
751 "The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}."
753 Clicking on the highlighted link will output
754 \tt{http://qt.nokia.com link activated} to the console.
758 \qmlproperty string Text::font.family
760 Sets the family name of the font.
762 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
763 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
764 If the family isn't available a family will be set using the font matching algorithm.
768 \qmlproperty bool Text::font.bold
770 Sets whether the font weight is bold.
774 \qmlproperty enumeration Text::font.weight
776 Sets the font's weight.
778 The weight can be one of:
781 \o Font.Normal - the default
788 Text { text: "Hello"; font.weight: Font.DemiBold }
793 \qmlproperty bool Text::font.italic
795 Sets whether the font has an italic style.
799 \qmlproperty bool Text::font.underline
801 Sets whether the text is underlined.
805 \qmlproperty bool Text::font.strikeout
807 Sets whether the font has a strikeout style.
811 \qmlproperty real Text::font.pointSize
813 Sets the font size in points. The point size must be greater than zero.
817 \qmlproperty int Text::font.pixelSize
819 Sets the font size in pixels.
821 Using this function makes the font device dependent.
822 Use \c pointSize to set the size of the font in a device independent manner.
826 \qmlproperty real Text::font.letterSpacing
828 Sets the letter spacing for the font.
830 Letter spacing changes the default spacing between individual letters in the font.
831 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
835 \qmlproperty real Text::font.wordSpacing
837 Sets the word spacing for the font.
839 Word spacing changes the default spacing between individual words.
840 A positive value increases the word spacing by a corresponding amount of pixels,
841 while a negative value decreases the inter-word spacing accordingly.
845 \qmlproperty enumeration Text::font.capitalization
847 Sets the capitalization for the text.
850 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
851 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
852 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
853 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
854 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
858 Text { text: "Hello"; font.capitalization: Font.AllLowercase }
861 QFont QDeclarativeText::font() const
863 Q_D(const QDeclarativeText);
864 return d->sourceFont;
867 void QDeclarativeText::setFont(const QFont &font)
869 Q_D(QDeclarativeText);
870 if (d->sourceFont == font)
873 d->sourceFont = font;
874 QFont oldFont = d->font;
876 if (d->font.pointSizeF() != -1) {
878 qreal size = qRound(d->font.pointSizeF()*2.0);
879 d->font.setPointSizeF(size/2.0);
882 if (oldFont != d->font)
885 emit fontChanged(d->sourceFont);
889 \qmlproperty string Text::text
891 The text to display. Text supports both plain and rich text strings.
893 The item will try to automatically determine whether the text should
894 be treated as rich text. This determination is made using Qt::mightBeRichText().
896 QString QDeclarativeText::text() const
898 Q_D(const QDeclarativeText);
902 void QDeclarativeText::setText(const QString &n)
904 Q_D(QDeclarativeText);
908 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n));
910 if (isComponentComplete()) {
914 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
916 d->rightToLeftText = d->text.isRightToLeft();
918 d->determineHorizontalAlignment();
921 emit textChanged(d->text);
926 \qmlproperty color Text::color
930 An example of green text defined using hexadecimal notation:
938 An example of steel blue text defined using an SVG color name:
946 QColor QDeclarativeText::color() const
948 Q_D(const QDeclarativeText);
952 void QDeclarativeText::setColor(const QColor &color)
954 Q_D(QDeclarativeText);
955 if (d->color == color)
959 d->invalidateImageCache();
960 emit colorChanged(d->color);
964 \qmlproperty enumeration Text::style
966 Set an additional text style.
968 Supported text styles are:
970 \o Text.Normal - the default
978 Text { font.pointSize: 24; text: "Normal" }
979 Text { font.pointSize: 24; text: "Raised"; style: Text.Raised; styleColor: "#AAAAAA" }
980 Text { font.pointSize: 24; text: "Outline";style: Text.Outline; styleColor: "red" }
981 Text { font.pointSize: 24; text: "Sunken"; style: Text.Sunken; styleColor: "#AAAAAA" }
985 \image declarative-textstyle.png
987 QDeclarativeText::TextStyle QDeclarativeText::style() const
989 Q_D(const QDeclarativeText);
993 void QDeclarativeText::setStyle(QDeclarativeText::TextStyle style)
995 Q_D(QDeclarativeText);
996 if (d->style == style)
999 // changing to/from Normal requires the boundingRect() to change
1000 if (isComponentComplete() && (d->style == Normal || style == Normal))
1001 prepareGeometryChange();
1003 d->invalidateImageCache();
1004 emit styleChanged(d->style);
1008 \qmlproperty color Text::styleColor
1010 Defines the secondary color used by text styles.
1012 \c styleColor is used as the outline color for outlined text, and as the
1013 shadow color for raised or sunken text. If no style has been set, it is not
1017 Text { font.pointSize: 18; text: "hello"; style: Text.Raised; styleColor: "gray" }
1022 QColor QDeclarativeText::styleColor() const
1024 Q_D(const QDeclarativeText);
1025 return d->styleColor;
1028 void QDeclarativeText::setStyleColor(const QColor &color)
1030 Q_D(QDeclarativeText);
1031 if (d->styleColor == color)
1034 d->styleColor = color;
1035 d->invalidateImageCache();
1036 emit styleColorChanged(d->styleColor);
1041 \qmlproperty enumeration Text::horizontalAlignment
1042 \qmlproperty enumeration Text::verticalAlignment
1043 \qmlproperty enumeration Text::effectiveHorizontalAlignment
1045 Sets the horizontal and vertical alignment of the text within the Text items
1046 width and height. By default, the text is vertically aligned to the top. Horizontal
1047 alignment follows the natural alignment of the text, for example text that is read
1048 from left to right will be aligned to the left.
1050 The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and
1051 \c Text.AlignJustify. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom
1052 and \c Text.AlignVCenter.
1054 Note that for a single line of text, the size of the text is the area of the text. In this common case,
1055 all alignments are equivalent. If you want the text to be, say, centered in its parent, then you will
1056 need to either modify the Item::anchors, or set horizontalAlignment to Text.AlignHCenter and bind the width to
1059 When using the attached property LayoutMirroring::enabled to mirror application
1060 layouts, the horizontal alignment of text will also be mirrored. However, the property
1061 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
1062 of Text, use the read-only property \c effectiveHorizontalAlignment.
1064 QDeclarativeText::HAlignment QDeclarativeText::hAlign() const
1066 Q_D(const QDeclarativeText);
1070 void QDeclarativeText::setHAlign(HAlignment align)
1072 Q_D(QDeclarativeText);
1073 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
1074 d->hAlignImplicit = false;
1075 if (d->setHAlign(align, forceAlign) && isComponentComplete())
1079 void QDeclarativeText::resetHAlign()
1081 Q_D(QDeclarativeText);
1082 d->hAlignImplicit = true;
1083 if (d->determineHorizontalAlignment() && isComponentComplete())
1087 QDeclarativeText::HAlignment QDeclarativeText::effectiveHAlign() const
1089 Q_D(const QDeclarativeText);
1090 QDeclarativeText::HAlignment effectiveAlignment = d->hAlign;
1091 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
1092 switch (d->hAlign) {
1093 case QDeclarativeText::AlignLeft:
1094 effectiveAlignment = QDeclarativeText::AlignRight;
1096 case QDeclarativeText::AlignRight:
1097 effectiveAlignment = QDeclarativeText::AlignLeft;
1103 return effectiveAlignment;
1106 bool QDeclarativeTextPrivate::setHAlign(QDeclarativeText::HAlignment alignment, bool forceAlign)
1108 Q_Q(QDeclarativeText);
1109 if (hAlign != alignment || forceAlign) {
1110 QDeclarativeText::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
1113 emit q->horizontalAlignmentChanged(hAlign);
1114 if (oldEffectiveHAlign != q->effectiveHAlign())
1115 emit q->effectiveHorizontalAlignmentChanged();
1121 bool QDeclarativeTextPrivate::determineHorizontalAlignment()
1123 Q_Q(QDeclarativeText);
1124 if (hAlignImplicit && q->isComponentComplete()) {
1125 bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
1126 return setHAlign(alignToRight ? QDeclarativeText::AlignRight : QDeclarativeText::AlignLeft);
1131 void QDeclarativeTextPrivate::mirrorChange()
1133 Q_Q(QDeclarativeText);
1134 if (q->isComponentComplete()) {
1135 if (!hAlignImplicit && (hAlign == QDeclarativeText::AlignRight || hAlign == QDeclarativeText::AlignLeft)) {
1137 emit q->effectiveHorizontalAlignmentChanged();
1142 QTextDocument *QDeclarativeTextPrivate::textDocument()
1147 QDeclarativeText::VAlignment QDeclarativeText::vAlign() const
1149 Q_D(const QDeclarativeText);
1153 void QDeclarativeText::setVAlign(VAlignment align)
1155 Q_D(QDeclarativeText);
1156 if (d->vAlign == align)
1159 if (isComponentComplete())
1160 prepareGeometryChange();
1162 emit verticalAlignmentChanged(align);
1166 \qmlproperty enumeration Text::wrapMode
1168 Set this property to wrap the text to the Text item's width. The text will only
1169 wrap if an explicit width has been set. wrapMode can be one of:
1172 \o Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l paintedWidth will exceed a set width.
1173 \o Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l paintedWidth will exceed a set width.
1174 \o Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
1175 \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.
1178 QDeclarativeText::WrapMode QDeclarativeText::wrapMode() const
1180 Q_D(const QDeclarativeText);
1184 void QDeclarativeText::setWrapMode(WrapMode mode)
1186 Q_D(QDeclarativeText);
1187 if (mode == d->wrapMode)
1193 emit wrapModeChanged();
1197 \qmlproperty int Text::lineCount
1200 Returns the number of lines visible in the text item.
1202 This property is not supported for rich text.
1204 \sa maximumLineCount
1206 int QDeclarativeText::lineCount() const
1208 Q_D(const QDeclarativeText);
1209 return d->lineCount;
1213 \qmlproperty bool Text::truncated
1216 Returns true if the text has been truncated due to \l maximumLineCount
1219 This property is not supported for rich text.
1221 \sa maximumLineCount, elide
1223 bool QDeclarativeText::truncated() const
1225 Q_D(const QDeclarativeText);
1226 return d->truncated;
1230 \qmlproperty int Text::maximumLineCount
1233 Set this property to limit the number of lines that the text item will show.
1234 If elide is set to Text.ElideRight, the text will be elided appropriately.
1235 By default, this is the value of the largest possible integer.
1237 This property is not supported for rich text.
1239 \sa lineCount, elide
1241 int QDeclarativeText::maximumLineCount() const
1243 Q_D(const QDeclarativeText);
1244 return d->maximumLineCount;
1247 void QDeclarativeText::setMaximumLineCount(int lines)
1249 Q_D(QDeclarativeText);
1251 d->maximumLineCountValid = lines==INT_MAX ? false : true;
1252 if (d->maximumLineCount != lines) {
1253 d->maximumLineCount = lines;
1255 emit maximumLineCountChanged();
1259 void QDeclarativeText::resetMaximumLineCount()
1261 Q_D(QDeclarativeText);
1262 setMaximumLineCount(INT_MAX);
1263 d->elidePos = QPointF();
1264 if (d->truncated != false) {
1265 d->truncated = false;
1266 emit truncatedChanged();
1271 \qmlproperty enumeration Text::textFormat
1273 The way the text property should be displayed.
1275 Supported text formats are:
1278 \o Text.AutoText (default)
1284 If the text format is \c Text.AutoText the text element
1285 will automatically determine whether the text should be treated as
1286 rich text. This determination is made using Qt::mightBeRichText().
1288 Text.StyledText is an optimized format supporting some basic text
1289 styling markup, in the style of html 3.2:
1292 <font size="4" color="#ff0000">font size and color</font>
1299 \c Text.StyledText parser is strict, requiring tags to be correctly nested.
1308 text: "<b>Hello</b> <i>World!</i>"
1312 textFormat: Text.RichText
1313 text: "<b>Hello</b> <i>World!</i>"
1317 textFormat: Text.PlainText
1318 text: "<b>Hello</b> <i>World!</i>"
1322 \o \image declarative-textformat.png
1325 QDeclarativeText::TextFormat QDeclarativeText::textFormat() const
1327 Q_D(const QDeclarativeText);
1331 void QDeclarativeText::setTextFormat(TextFormat format)
1333 Q_D(QDeclarativeText);
1334 if (format == d->format)
1337 bool wasRich = d->richText;
1338 d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
1340 if (!wasRich && d->richText && isComponentComplete()) {
1342 d->doc->setText(d->text);
1347 emit textFormatChanged(d->format);
1351 \qmlproperty enumeration Text::elide
1353 Set this property to elide parts of the text fit to the Text item's width.
1354 The text will only elide if an explicit width has been set.
1356 This property cannot be used with rich text.
1360 \o Text.ElideNone - the default
1366 If this property is set to Text.ElideRight, it can be used with multiline
1367 text. The text will only elide if maximumLineCount has been set.
1369 If the text is a multi-length string, and the mode is not \c Text.ElideNone,
1370 the first string that fits will be used, otherwise the last will be elided.
1372 Multi-length strings are ordered from longest to shortest, separated by the
1373 Unicode "String Terminator" character \c U009C (write this in QML with \c{"\u009C"} or \c{"\x9C"}).
1375 QDeclarativeText::TextElideMode QDeclarativeText::elideMode() const
1377 Q_D(const QDeclarativeText);
1378 return d->elideMode;
1381 void QDeclarativeText::setElideMode(QDeclarativeText::TextElideMode mode)
1383 Q_D(QDeclarativeText);
1384 if (mode == d->elideMode)
1387 d->elideMode = mode;
1390 emit elideModeChanged(d->elideMode);
1394 QRectF QDeclarativeText::boundingRect() const
1396 Q_D(const QDeclarativeText);
1398 QRect rect = d->layedOutTextRect;
1399 if (d->style != Normal)
1400 rect.adjust(-1, 0, 1, 2);
1402 // Could include font max left/right bearings to either side of rectangle.
1405 switch (d->vAlign) {
1409 rect.moveTop(h - rect.height());
1412 rect.moveTop((h - rect.height()) / 2);
1416 return QRectF(rect);
1420 void QDeclarativeText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
1422 Q_D(QDeclarativeText);
1423 if ((!d->internalWidthUpdate && newGeometry.width() != oldGeometry.width())
1424 && (d->wrapMode != QDeclarativeText::NoWrap
1425 || d->elideMode != QDeclarativeText::ElideNone
1426 || d->hAlign != QDeclarativeText::AlignLeft)) {
1427 if ((d->singleline || d->maximumLineCountValid) && d->elideMode != QDeclarativeText::ElideNone && widthValid()) {
1428 // We need to re-elide
1431 // We just need to re-layout
1436 QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
1440 \qmlproperty real Text::paintedWidth
1442 Returns the width of the text, including width past the width
1443 which is covered due to insufficient wrapping if WrapMode is set.
1445 qreal QDeclarativeText::paintedWidth() const
1447 Q_D(const QDeclarativeText);
1448 return d->paintedSize.width();
1452 \qmlproperty real Text::paintedHeight
1454 Returns the height of the text, including height past the height
1455 which is covered due to there being more text than fits in the set height.
1457 qreal QDeclarativeText::paintedHeight() const
1459 Q_D(const QDeclarativeText);
1460 return d->paintedSize.height();
1464 \qmlproperty real Text::lineHeight
1467 Sets the line height for the text.
1468 The value can be in pixels or a multiplier depending on lineHeightMode.
1470 The default value is a multiplier of 1.0.
1471 The line height must be a positive value.
1473 qreal QDeclarativeText::lineHeight() const
1475 Q_D(const QDeclarativeText);
1476 return d->lineHeight;
1479 void QDeclarativeText::setLineHeight(qreal lineHeight)
1481 Q_D(QDeclarativeText);
1483 if ((d->lineHeight == lineHeight) || (lineHeight < 0.0))
1486 d->lineHeight = lineHeight;
1488 emit lineHeightChanged(lineHeight);
1492 \qmlproperty enumeration Text::lineHeightMode
1494 This property determines how the line height is specified.
1495 The possible values are:
1498 \o Text.ProportionalHeight (default) - this sets the spacing proportional to the
1499 line (as a multiplier). For example, set to 2 for double spacing.
1500 \o Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
1503 QDeclarativeText::LineHeightMode QDeclarativeText::lineHeightMode() const
1505 Q_D(const QDeclarativeText);
1506 return d->lineHeightMode;
1509 void QDeclarativeText::setLineHeightMode(LineHeightMode mode)
1511 Q_D(QDeclarativeText);
1512 if (mode == d->lineHeightMode)
1515 d->lineHeightMode = mode;
1518 emit lineHeightModeChanged(mode);
1522 Returns the number of resources (images) that are being loaded asynchronously.
1524 int QDeclarativeText::resourcesLoading() const
1526 Q_D(const QDeclarativeText);
1527 return d->doc ? d->doc->resourcesLoading() : 0;
1531 void QDeclarativeText::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
1533 Q_D(QDeclarativeText);
1535 if (d->cacheAllTextAsImage || d->style != Normal) {
1536 d->checkImageCache();
1537 if (d->imageCache.isNull())
1540 bool oldAA = p->testRenderHint(QPainter::Antialiasing);
1541 bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform);
1543 p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth);
1545 QRect br = boundingRect().toRect();
1547 bool needClip = clip() && (d->imageCache.width() > width() ||
1548 d->imageCache.height() > height());
1551 p->drawPixmap(0, 0, width(), height(), d->imageCache, -br.x(), -br.y(), width(), height());
1553 p->drawPixmap(br.x(), br.y(), d->imageCache);
1556 p->setRenderHint(QPainter::Antialiasing, oldAA);
1557 p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth);
1560 QRectF bounds = boundingRect();
1562 bool needClip = clip() && (d->layedOutTextRect.width() > width() ||
1563 d->layedOutTextRect.height() > height());
1567 p->setClipRect(0, 0, width(), height(), Qt::IntersectClip);
1570 QAbstractTextDocumentLayout::PaintContext context;
1571 context.palette.setColor(QPalette::Text, d->color);
1572 p->translate(bounds.x(), bounds.y());
1573 d->doc->documentLayout()->draw(p, context);
1574 p->translate(-bounds.x(), -bounds.y());
1576 d->drawTextLayout(p, QPointF(0, bounds.y()), false);
1586 void QDeclarativeText::componentComplete()
1588 Q_D(QDeclarativeText);
1589 QDeclarativeItem::componentComplete();
1590 if (d->updateOnComponentComplete) {
1591 d->updateOnComponentComplete = false;
1594 d->doc->setText(d->text);
1595 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1597 d->rightToLeftText = d->text.isRightToLeft();
1599 d->determineHorizontalAlignment();
1605 void QDeclarativeText::mousePressEvent(QGraphicsSceneMouseEvent *event)
1607 Q_D(QDeclarativeText);
1609 if (!d->richText || !d->doc || d->doc->documentLayout()->anchorAt(event->pos()).isEmpty()) {
1610 event->setAccepted(false);
1611 d->activeLink.clear();
1613 d->activeLink = d->doc->documentLayout()->anchorAt(event->pos());
1616 // ### may malfunction if two of the same links are clicked & dragged onto each other)
1618 if (!event->isAccepted())
1619 QDeclarativeItem::mousePressEvent(event);
1624 void QDeclarativeText::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1626 Q_D(QDeclarativeText);
1628 // ### confirm the link, and send a signal out
1629 if (d->richText && d->doc && d->activeLink == d->doc->documentLayout()->anchorAt(event->pos()))
1630 emit linkActivated(d->activeLink);
1632 event->setAccepted(false);
1634 if (!event->isAccepted())
1635 QDeclarativeItem::mouseReleaseEvent(event);
1640 #include "qdeclarativetext.moc"