1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "QtQuick1/private/qdeclarativetext_p.h"
43 #include "QtQuick1/private/qdeclarativetext_p_p.h"
44 #include "QtQuick1/private/qdeclarativestyledtext_p.h"
45 #include <QtDeclarative/qdeclarativeinfo.h>
46 #include "QtQuick1/private/qdeclarativepixmapcache_p.h"
49 #include <QTextLayout>
51 #include <QTextDocument>
52 #include <QGraphicsSceneMouseEvent>
54 #include <QAbstractTextDocumentLayout>
62 extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
64 class QTextDocumentWithImageResources_1 : public QTextDocument {
68 QTextDocumentWithImageResources_1(QDeclarative1Text *parent);
69 virtual ~QTextDocumentWithImageResources_1();
71 void setText(const QString &);
72 int resourcesLoading() const { return outstanding; }
75 QVariant loadResource(int type, const QUrl &name);
78 void requestFinished();
81 QHash<QUrl, QDeclarative1Pixmap *> m_resources;
84 static QSet<QUrl> errors;
88 QTextDocumentWithImageResources_1::QTextDocumentWithImageResources_1(QDeclarative1Text *parent)
89 : QTextDocument(parent), outstanding(0)
93 QTextDocumentWithImageResources_1::~QTextDocumentWithImageResources_1()
95 if (!m_resources.isEmpty())
96 qDeleteAll(m_resources);
99 QVariant QTextDocumentWithImageResources_1::loadResource(int type, const QUrl &name)
101 QDeclarativeContext *context = qmlContext(parent());
102 QUrl url = context->resolvedUrl(name);
104 if (type == QTextDocument::ImageResource) {
105 QHash<QUrl, QDeclarative1Pixmap *>::Iterator iter = m_resources.find(url);
107 if (iter == m_resources.end()) {
108 QDeclarative1Pixmap *p = new QDeclarative1Pixmap(context->engine(), url);
109 iter = m_resources.insert(name, p);
111 if (p->isLoading()) {
112 p->connectFinished(this, SLOT(requestFinished()));
117 QDeclarative1Pixmap *p = *iter;
120 } else if (p->isError()) {
121 if (!errors.contains(url)) {
123 qmlInfo(parent()) << p->error();
128 return QTextDocument::loadResource(type,url); // The *resolved* URL
131 void QTextDocumentWithImageResources_1::requestFinished()
134 if (outstanding == 0) {
135 QDeclarative1Text *textItem = static_cast<QDeclarative1Text*>(parent());
136 QString text = textItem->text();
137 #ifndef QT_NO_TEXTHTMLPARSER
142 QDeclarative1TextPrivate *d = QDeclarative1TextPrivate::get(textItem);
147 void QTextDocumentWithImageResources_1::setText(const QString &text)
149 if (!m_resources.isEmpty()) {
150 qDeleteAll(m_resources);
155 #ifndef QT_NO_TEXTHTMLPARSER
162 QSet<QUrl> QTextDocumentWithImageResources_1::errors;
164 QDeclarative1TextPrivate::~QDeclarative1TextPrivate()
168 DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE);
170 QString QDeclarative1TextPrivate::elideChar = QString(0x2026);
172 QDeclarative1TextPrivate::QDeclarative1TextPrivate()
173 : color((QRgb)0), style(QDeclarative1Text::Normal), hAlign(QDeclarative1Text::AlignLeft),
174 vAlign(QDeclarative1Text::AlignTop), elideMode(QDeclarative1Text::ElideNone),
175 format(QDeclarative1Text::AutoText), wrapMode(QDeclarative1Text::NoWrap), lineHeight(1),
176 lineHeightMode(QDeclarative1Text::ProportionalHeight), lineCount(1), truncated(false), maximumLineCount(INT_MAX),
177 maximumLineCountValid(false), imageCacheDirty(true), updateOnComponentComplete(true), richText(false), singleline(false),
178 cacheAllTextAsImage(true), internalWidthUpdate(false), requireImplicitWidth(false), hAlignImplicit(true),
179 rightToLeftText(false), layoutTextElided(false), naturalWidth(0), doc(0)
181 cacheAllTextAsImage = enableImageCache();
182 QGraphicsItemPrivate::acceptedMouseButtons = Qt::LeftButton;
183 QGraphicsItemPrivate::flags = QGraphicsItemPrivate::flags & ~QGraphicsItem::ItemHasNoContents;
186 qreal QDeclarative1TextPrivate::implicitWidth() const
188 if (!requireImplicitWidth) {
189 // We don't calculate implicitWidth unless it is required.
190 // We need to force a size update now to ensure implicitWidth is calculated
191 QDeclarative1TextPrivate *me = const_cast<QDeclarative1TextPrivate*>(this);
192 me->requireImplicitWidth = true;
195 return mImplicitWidth;
198 void QDeclarative1TextPrivate::updateLayout()
200 Q_Q(QDeclarative1Text);
201 if (!q->isComponentComplete()) {
202 updateOnComponentComplete = true;
206 layoutTextElided = false;
207 // Setup instance of QTextLayout for all cases other than richtext
209 layout.clearLayout();
210 layout.setFont(font);
211 if (format != QDeclarative1Text::StyledText) {
213 tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
214 singleline = !tmp.contains(QChar::LineSeparator);
215 if (singleline && !maximumLineCountValid && elideMode != QDeclarative1Text::ElideNone && q->widthValid()) {
216 QFontMetrics fm(font);
217 tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width());
219 layoutTextElided = true;
222 emit q->truncatedChanged();
229 QDeclarative1StyledText::parse(text, layout);
236 void QDeclarative1TextPrivate::updateSize()
238 Q_Q(QDeclarative1Text);
240 if (!q->isComponentComplete()) {
241 updateOnComponentComplete = true;
245 if (!requireImplicitWidth) {
246 emit q->implicitWidthChanged();
247 // if the implicitWidth is used, then updateSize() has already been called (recursively)
248 if (requireImplicitWidth)
252 invalidateImageCache();
254 QFontMetrics fm(font);
255 if (text.isEmpty()) {
256 q->setImplicitWidth(0);
257 q->setImplicitHeight(fm.height());
258 paintedSize = QSize(0, fm.height());
259 emit q->paintedSizeChanged();
264 int dy = q->height();
267 //setup instance of QTextLayout for all cases other than richtext
269 QRect textRect = setupTextLayout();
270 if (layedOutTextRect.size() != textRect.size())
271 q->prepareGeometryChange();
272 layedOutTextRect = textRect;
273 size = textRect.size();
276 singleline = false; // richtext can't elide or be optimized for single-line case
278 doc->setDefaultFont(font);
280 QDeclarative1Text::HAlignment horizontalAlignment = q->effectiveHAlign();
281 if (rightToLeftText) {
282 if (horizontalAlignment == QDeclarative1Text::AlignLeft)
283 horizontalAlignment = QDeclarative1Text::AlignRight;
284 else if (horizontalAlignment == QDeclarative1Text::AlignRight)
285 horizontalAlignment = QDeclarative1Text::AlignLeft;
288 option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
289 option.setWrapMode(QTextOption::WrapMode(wrapMode));
290 doc->setDefaultTextOption(option);
291 if (requireImplicitWidth && q->widthValid()) {
292 doc->setTextWidth(-1);
293 naturalWidth = doc->idealWidth();
295 if (wrapMode != QDeclarative1Text::NoWrap && q->widthValid())
296 doc->setTextWidth(q->width());
298 doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
299 dy -= (int)doc->size().height();
300 QSize dsize = doc->size().toSize();
301 if (dsize != layedOutTextRect.size()) {
302 q->prepareGeometryChange();
303 layedOutTextRect = QRect(QPoint(0,0), dsize);
305 size = QSize(int(doc->idealWidth()),dsize.height());
309 if (q->heightValid()) {
310 if (vAlign == QDeclarative1Text::AlignBottom)
312 else if (vAlign == QDeclarative1Text::AlignVCenter)
315 q->setBaselineOffset(fm.ascent() + yoff);
317 //### need to comfirm cost of always setting these for richText
318 internalWidthUpdate = true;
319 if (!q->widthValid())
320 q->setImplicitWidth(size.width());
321 else if (requireImplicitWidth)
322 q->setImplicitWidth(naturalWidth);
323 internalWidthUpdate = false;
324 q->setImplicitHeight(size.height());
325 if (paintedSize != size) {
327 emit q->paintedSizeChanged();
333 Lays out the QDeclarative1TextPrivate::layout QTextLayout in the constraints of the QDeclarative1Text.
335 Returns the size of the final text. This can be used to position the text vertically (the text is
336 already absolutely positioned horizontally).
338 QRect QDeclarative1TextPrivate::setupTextLayout()
340 // ### text layout handling should be profiled and optimized as needed
341 // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
342 Q_Q(QDeclarative1Text);
343 layout.setCacheEnabled(true);
346 int visibleCount = 0;
350 lineWidth = q->width();
352 QTextOption textOption = layout.textOption();
353 textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
354 textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
355 layout.setTextOption(textOption);
357 bool elideText = false;
358 bool truncate = false;
360 QFontMetrics fm(layout.font());
361 elidePos = QPointF();
363 if (requireImplicitWidth && q->widthValid()) {
364 // requires an extra layout
366 if (layoutTextElided) {
367 // We have provided elided text to the layout, but we must calculate unelided width.
368 elidedText = layout.text();
369 layout.setText(text);
371 layout.beginLayout();
373 QTextLine line = layout.createLine();
379 for (int i = 0; i < layout.lineCount(); ++i) {
380 QTextLine line = layout.lineAt(i);
381 br = br.united(line.naturalTextRect());
383 naturalWidth = br.width();
384 if (layoutTextElided)
385 layout.setText(elidedText);
388 if (maximumLineCountValid) {
389 layout.beginLayout();
392 int linesLeft = maximumLineCount;
393 int visibleTextLength = 0;
394 while (linesLeft > 0) {
395 QTextLine line = layout.createLine();
401 line.setLineWidth(lineWidth);
402 visibleTextLength += line.textLength();
404 if (--linesLeft == 0) {
405 if (visibleTextLength < text.length()) {
407 if (elideMode==QDeclarative1Text::ElideRight && q->widthValid()) {
408 qreal elideWidth = fm.width(elideChar);
409 // Need to correct for alignment
410 line.setLineWidth(lineWidth-elideWidth);
411 if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) {
412 line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y()));
413 elidePos.setX(line.naturalTextRect().left() - elideWidth);
415 elidePos.setX(line.naturalTextRect().right());
425 if (truncated != truncate) {
426 truncated = truncate;
427 emit q->truncatedChanged();
430 layout.beginLayout();
432 QTextLine line = layout.createLine();
437 line.setLineWidth(lineWidth);
444 for (int i = 0; i < layout.lineCount(); ++i) {
445 QTextLine line = layout.lineAt(i);
447 line.setPosition(QPointF(line.position().x(), height));
448 if (elideText && i == layout.lineCount()-1) {
449 elidePos.setY(height + fm.ascent());
450 br = br.united(QRectF(elidePos, QSizeF(fm.width(elideChar), fm.ascent())));
452 br = br.united(line.naturalTextRect());
453 height += (lineHeightMode == QDeclarative1Text::FixedHeight) ? lineHeight : line.height() * lineHeight;
455 br.setHeight(height);
457 if (!q->widthValid())
458 naturalWidth = br.width();
460 //Update the number of visible lines
461 if (lineCount != visibleCount) {
462 lineCount = visibleCount;
463 emit q->lineCountChanged();
466 return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height()));
470 Returns a painted version of the QDeclarative1TextPrivate::layout QTextLayout.
471 If \a drawStyle is true, the style color overrides all colors in the document.
473 QPixmap QDeclarative1TextPrivate::textLayoutImage(bool drawStyle)
476 QSize size = layedOutTextRect.size();
479 if (!size.isEmpty()) {
480 img.fill(Qt::transparent);
482 bool oldSmooth = qt_applefontsmoothing_enabled;
483 qt_applefontsmoothing_enabled = false;
487 qt_applefontsmoothing_enabled = oldSmooth;
489 drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle);
495 Paints the QDeclarative1TextPrivate::layout QTextLayout into \a painter at \a pos. If
496 \a drawStyle is true, the style color overrides all colors in the document.
498 void QDeclarative1TextPrivate::drawTextLayout(QPainter *painter, const QPointF &pos, bool drawStyle)
501 painter->setPen(styleColor);
503 painter->setPen(color);
504 painter->setFont(font);
505 layout.draw(painter, pos);
506 if (!elidePos.isNull())
507 painter->drawText(pos + elidePos, elideChar);
511 Returns a painted version of the QDeclarative1TextPrivate::doc QTextDocument.
512 If \a drawStyle is true, the style color overrides all colors in the document.
514 QPixmap QDeclarative1TextPrivate::textDocumentImage(bool drawStyle)
516 QSize size = doc->size().toSize();
520 img.fill(Qt::transparent);
522 bool oldSmooth = qt_applefontsmoothing_enabled;
523 qt_applefontsmoothing_enabled = false;
527 qt_applefontsmoothing_enabled = oldSmooth;
530 QAbstractTextDocumentLayout::PaintContext context;
532 QTextOption oldOption(doc->defaultTextOption());
534 context.palette.setColor(QPalette::Text, styleColor);
535 QTextOption colorOption(doc->defaultTextOption());
536 colorOption.setFlags(QTextOption::SuppressColors);
537 doc->setDefaultTextOption(colorOption);
539 context.palette.setColor(QPalette::Text, color);
541 doc->documentLayout()->draw(&p, context);
543 doc->setDefaultTextOption(oldOption);
548 Mark the image cache as dirty.
550 void QDeclarative1TextPrivate::invalidateImageCache()
552 Q_Q(QDeclarative1Text);
554 if(cacheAllTextAsImage || style != QDeclarative1Text::Normal){//If actually using the image cache
558 imageCacheDirty = true;
559 imageCache = QPixmap();
561 if (q->isComponentComplete())
566 Tests if the image cache is dirty, and repaints it if it is.
568 void QDeclarative1TextPrivate::checkImageCache()
570 if (!imageCacheDirty)
573 if (text.isEmpty()) {
575 imageCache = QPixmap();
583 textImage = textDocumentImage(false);
584 if (style != QDeclarative1Text::Normal)
585 styledImage = textDocumentImage(true); //### should use styleColor
587 textImage = textLayoutImage(false);
588 if (style != QDeclarative1Text::Normal)
589 styledImage = textLayoutImage(true); //### should use styleColor
593 case QDeclarative1Text::Outline:
594 imageCache = drawOutline(textImage, styledImage);
596 case QDeclarative1Text::Sunken:
597 imageCache = drawOutline(textImage, styledImage, -1);
599 case QDeclarative1Text::Raised:
600 imageCache = drawOutline(textImage, styledImage, 1);
603 imageCache = textImage;
609 imageCacheDirty = false;
613 Ensures the QDeclarative1TextPrivate::doc variable is set to a valid text document
615 void QDeclarative1TextPrivate::ensureDoc()
618 Q_Q(QDeclarative1Text);
619 doc = new QTextDocumentWithImageResources_1(q);
620 doc->setDocumentMargin(0);
625 Draw \a styleSource as an outline around \a source and return the new image.
627 QPixmap QDeclarative1TextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource)
629 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
630 img.fill(Qt::transparent);
635 pos += QPoint(-1, 0);
636 ppm.drawPixmap(pos, styleSource);
638 ppm.drawPixmap(pos, styleSource);
639 pos += QPoint(-1, -1);
640 ppm.drawPixmap(pos, styleSource);
642 ppm.drawPixmap(pos, styleSource);
644 pos += QPoint(0, -1);
645 ppm.drawPixmap(pos, source);
652 Draw \a styleSource below \a source at \a yOffset and return the new image.
654 QPixmap QDeclarative1TextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset)
656 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
657 img.fill(Qt::transparent);
661 ppm.drawPixmap(QPoint(0, yOffset), styleSource);
662 ppm.drawPixmap(0, 0, source);
670 \qmlclass Text QDeclarative1Text
671 \inqmlmodule QtQuick 1
672 \ingroup qml-basic-visual-elements
674 \brief The Text item allows you to add formatted text to a scene.
677 Text items can display both plain and rich text. For example, red text with
678 a specific font and size can be defined like this:
683 font.family: "Helvetica"
689 Rich text is defined using HTML-style markup:
693 text: "<b>Hello</b> <i>World!</i>"
697 \image declarative-text.png
699 If height and width are not explicitly set, Text will attempt to determine how
700 much room is needed and set it accordingly. Unless \l wrapMode is set, it will always
701 prefer width to height (all text will be placed on a single line).
703 The \l elide property can alternatively be used to fit a single line of
704 plain text to a set width.
706 Note that the \l{Supported HTML Subset} is limited. Also, if the text contains
707 HTML img tags that load remote images, the text is reloaded.
709 Text provides read-only text. For editable text, see \l TextEdit.
711 \sa {declarative/text/fonts}{Fonts example}
713 QDeclarative1Text::QDeclarative1Text(QDeclarativeItem *parent)
714 : QDeclarative1ImplicitSizeItem(*(new QDeclarative1TextPrivate), parent)
718 QDeclarative1Text::~QDeclarative1Text()
723 \qmlproperty bool QtQuick1::Text::clip
724 This property holds whether the text is clipped.
726 Note that if the text does not fit in the bounding rectangle it will be abruptly chopped.
728 If you want to display potentially long text in a limited space, you probably want to use \c elide instead.
732 \qmlproperty bool QtQuick1::Text::smooth
734 This property holds whether the text is smoothly scaled or transformed.
736 Smooth filtering gives better visual quality, but is slower. If
737 the item is displayed at its natural size, this property has no visual or
740 \note Generally scaling artifacts are only visible if the item is stationary on
741 the screen. A common pattern when animating an item is to disable smooth
742 filtering at the beginning of the animation and reenable it at the conclusion.
746 \qmlsignal QtQuick1::Text::onLinkActivated(string link)
748 This handler is called when the user clicks on a link embedded in the text.
749 The link must be in rich text or HTML format and the
750 \a link string provides access to the particular link.
752 \snippet doc/src/snippets/declarative/text/onLinkActivated.qml 0
754 The example code will display the text
755 "The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}."
757 Clicking on the highlighted link will output
758 \tt{http://qt.nokia.com link activated} to the console.
762 \qmlproperty string QtQuick1::Text::font.family
764 Sets the family name of the font.
766 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
767 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
768 If the family isn't available a family will be set using the font matching algorithm.
772 \qmlproperty bool QtQuick1::Text::font.bold
774 Sets whether the font weight is bold.
778 \qmlproperty enumeration QtQuick1::Text::font.weight
780 Sets the font's weight.
782 The weight can be one of:
785 \o Font.Normal - the default
792 Text { text: "Hello"; font.weight: Font.DemiBold }
797 \qmlproperty bool QtQuick1::Text::font.italic
799 Sets whether the font has an italic style.
803 \qmlproperty bool QtQuick1::Text::font.underline
805 Sets whether the text is underlined.
809 \qmlproperty bool QtQuick1::Text::font.strikeout
811 Sets whether the font has a strikeout style.
815 \qmlproperty real QtQuick1::Text::font.pointSize
817 Sets the font size in points. The point size must be greater than zero.
821 \qmlproperty int QtQuick1::Text::font.pixelSize
823 Sets the font size in pixels.
825 Using this function makes the font device dependent.
826 Use \c pointSize to set the size of the font in a device independent manner.
830 \qmlproperty real QtQuick1::Text::font.letterSpacing
832 Sets the letter spacing for the font.
834 Letter spacing changes the default spacing between individual letters in the font.
835 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
839 \qmlproperty real QtQuick1::Text::font.wordSpacing
841 Sets the word spacing for the font.
843 Word spacing changes the default spacing between individual words.
844 A positive value increases the word spacing by a corresponding amount of pixels,
845 while a negative value decreases the inter-word spacing accordingly.
849 \qmlproperty enumeration QtQuick1::Text::font.capitalization
851 Sets the capitalization for the text.
854 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
855 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
856 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
857 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
858 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
862 Text { text: "Hello"; font.capitalization: Font.AllLowercase }
865 QFont QDeclarative1Text::font() const
867 Q_D(const QDeclarative1Text);
868 return d->sourceFont;
871 void QDeclarative1Text::setFont(const QFont &font)
873 Q_D(QDeclarative1Text);
874 if (d->sourceFont == font)
877 d->sourceFont = font;
878 QFont oldFont = d->font;
880 if (d->font.pointSizeF() != -1) {
882 qreal size = qRound(d->font.pointSizeF()*2.0);
883 d->font.setPointSizeF(size/2.0);
886 if (oldFont != d->font)
889 emit fontChanged(d->sourceFont);
893 \qmlproperty string QtQuick1::Text::text
895 The text to display. Text supports both plain and rich text strings.
897 The item will try to automatically determine whether the text should
898 be treated as rich text. This determination is made using Qt::mightBeRichText().
900 QString QDeclarative1Text::text() const
902 Q_D(const QDeclarative1Text);
906 void QDeclarative1Text::setText(const QString &n)
908 Q_D(QDeclarative1Text);
912 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n));
914 if (isComponentComplete()) {
918 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
920 d->rightToLeftText = d->text.isRightToLeft();
922 d->determineHorizontalAlignment();
925 emit textChanged(d->text);
930 \qmlproperty color QtQuick1::Text::color
934 An example of green text defined using hexadecimal notation:
942 An example of steel blue text defined using an SVG color name:
950 QColor QDeclarative1Text::color() const
952 Q_D(const QDeclarative1Text);
956 void QDeclarative1Text::setColor(const QColor &color)
958 Q_D(QDeclarative1Text);
959 if (d->color == color)
963 d->invalidateImageCache();
964 emit colorChanged(d->color);
968 \qmlproperty enumeration QtQuick1::Text::style
970 Set an additional text style.
972 Supported text styles are:
974 \o Text.Normal - the default
982 Text { font.pointSize: 24; text: "Normal" }
983 Text { font.pointSize: 24; text: "Raised"; style: Text.Raised; styleColor: "#AAAAAA" }
984 Text { font.pointSize: 24; text: "Outline";style: Text.Outline; styleColor: "red" }
985 Text { font.pointSize: 24; text: "Sunken"; style: Text.Sunken; styleColor: "#AAAAAA" }
989 \image declarative-textstyle.png
991 QDeclarative1Text::TextStyle QDeclarative1Text::style() const
993 Q_D(const QDeclarative1Text);
997 void QDeclarative1Text::setStyle(QDeclarative1Text::TextStyle style)
999 Q_D(QDeclarative1Text);
1000 if (d->style == style)
1003 // changing to/from Normal requires the boundingRect() to change
1004 if (isComponentComplete() && (d->style == Normal || style == Normal))
1005 prepareGeometryChange();
1007 d->invalidateImageCache();
1008 emit styleChanged(d->style);
1012 \qmlproperty color QtQuick1::Text::styleColor
1014 Defines the secondary color used by text styles.
1016 \c styleColor is used as the outline color for outlined text, and as the
1017 shadow color for raised or sunken text. If no style has been set, it is not
1021 Text { font.pointSize: 18; text: "hello"; style: Text.Raised; styleColor: "gray" }
1026 QColor QDeclarative1Text::styleColor() const
1028 Q_D(const QDeclarative1Text);
1029 return d->styleColor;
1032 void QDeclarative1Text::setStyleColor(const QColor &color)
1034 Q_D(QDeclarative1Text);
1035 if (d->styleColor == color)
1038 d->styleColor = color;
1039 d->invalidateImageCache();
1040 emit styleColorChanged(d->styleColor);
1045 \qmlproperty enumeration QtQuick1::Text::horizontalAlignment
1046 \qmlproperty enumeration QtQuick1::Text::verticalAlignment
1047 \qmlproperty enumeration QtQuick1::Text::effectiveHorizontalAlignment
1049 Sets the horizontal and vertical alignment of the text within the Text items
1050 width and height. By default, the text is vertically aligned to the top. Horizontal
1051 alignment follows the natural alignment of the text, for example text that is read
1052 from left to right will be aligned to the left.
1054 The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and
1055 \c Text.AlignJustify. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom
1056 and \c Text.AlignVCenter.
1058 Note that for a single line of text, the size of the text is the area of the text. In this common case,
1059 all alignments are equivalent. If you want the text to be, say, centered in its parent, then you will
1060 need to either modify the Item::anchors, or set horizontalAlignment to Text.AlignHCenter and bind the width to
1063 When using the attached property LayoutMirroring::enabled to mirror application
1064 layouts, the horizontal alignment of text will also be mirrored. However, the property
1065 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
1066 of Text, use the read-only property \c effectiveHorizontalAlignment.
1068 QDeclarative1Text::HAlignment QDeclarative1Text::hAlign() const
1070 Q_D(const QDeclarative1Text);
1074 void QDeclarative1Text::setHAlign(HAlignment align)
1076 Q_D(QDeclarative1Text);
1077 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
1078 d->hAlignImplicit = false;
1079 if (d->setHAlign(align, forceAlign) && isComponentComplete())
1083 void QDeclarative1Text::resetHAlign()
1085 Q_D(QDeclarative1Text);
1086 d->hAlignImplicit = true;
1087 if (d->determineHorizontalAlignment() && isComponentComplete())
1091 QDeclarative1Text::HAlignment QDeclarative1Text::effectiveHAlign() const
1093 Q_D(const QDeclarative1Text);
1094 QDeclarative1Text::HAlignment effectiveAlignment = d->hAlign;
1095 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
1096 switch (d->hAlign) {
1097 case QDeclarative1Text::AlignLeft:
1098 effectiveAlignment = QDeclarative1Text::AlignRight;
1100 case QDeclarative1Text::AlignRight:
1101 effectiveAlignment = QDeclarative1Text::AlignLeft;
1107 return effectiveAlignment;
1110 bool QDeclarative1TextPrivate::setHAlign(QDeclarative1Text::HAlignment alignment, bool forceAlign)
1112 Q_Q(QDeclarative1Text);
1113 if (hAlign != alignment || forceAlign) {
1114 QDeclarative1Text::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
1117 emit q->horizontalAlignmentChanged(hAlign);
1118 if (oldEffectiveHAlign != q->effectiveHAlign())
1119 emit q->effectiveHorizontalAlignmentChanged();
1125 bool QDeclarative1TextPrivate::determineHorizontalAlignment()
1127 Q_Q(QDeclarative1Text);
1128 if (hAlignImplicit && q->isComponentComplete()) {
1129 bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
1130 return setHAlign(alignToRight ? QDeclarative1Text::AlignRight : QDeclarative1Text::AlignLeft);
1135 void QDeclarative1TextPrivate::mirrorChange()
1137 Q_Q(QDeclarative1Text);
1138 if (q->isComponentComplete()) {
1139 if (!hAlignImplicit && (hAlign == QDeclarative1Text::AlignRight || hAlign == QDeclarative1Text::AlignLeft)) {
1141 emit q->effectiveHorizontalAlignmentChanged();
1146 QTextDocument *QDeclarative1TextPrivate::textDocument()
1151 QDeclarative1Text::VAlignment QDeclarative1Text::vAlign() const
1153 Q_D(const QDeclarative1Text);
1157 void QDeclarative1Text::setVAlign(VAlignment align)
1159 Q_D(QDeclarative1Text);
1160 if (d->vAlign == align)
1163 if (isComponentComplete())
1164 prepareGeometryChange();
1166 emit verticalAlignmentChanged(align);
1170 \qmlproperty enumeration QtQuick1::Text::wrapMode
1172 Set this property to wrap the text to the Text item's width. The text will only
1173 wrap if an explicit width has been set. wrapMode can be one of:
1176 \o Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l paintedWidth will exceed a set width.
1177 \o Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l paintedWidth will exceed a set width.
1178 \o Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
1179 \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.
1182 QDeclarative1Text::WrapMode QDeclarative1Text::wrapMode() const
1184 Q_D(const QDeclarative1Text);
1188 void QDeclarative1Text::setWrapMode(WrapMode mode)
1190 Q_D(QDeclarative1Text);
1191 if (mode == d->wrapMode)
1197 emit wrapModeChanged();
1201 \qmlproperty int QtQuick1::Text::lineCount
1204 Returns the number of lines visible in the text item.
1206 This property is not supported for rich text.
1208 \sa maximumLineCount
1210 int QDeclarative1Text::lineCount() const
1212 Q_D(const QDeclarative1Text);
1213 return d->lineCount;
1217 \qmlproperty bool QtQuick1::Text::truncated
1220 Returns true if the text has been truncated due to \l maximumLineCount
1223 This property is not supported for rich text.
1225 \sa maximumLineCount, elide
1227 bool QDeclarative1Text::truncated() const
1229 Q_D(const QDeclarative1Text);
1230 return d->truncated;
1234 \qmlproperty int QtQuick1::Text::maximumLineCount
1237 Set this property to limit the number of lines that the text item will show.
1238 If elide is set to Text.ElideRight, the text will be elided appropriately.
1239 By default, this is the value of the largest possible integer.
1241 This property is not supported for rich text.
1243 \sa lineCount, elide
1245 int QDeclarative1Text::maximumLineCount() const
1247 Q_D(const QDeclarative1Text);
1248 return d->maximumLineCount;
1251 void QDeclarative1Text::setMaximumLineCount(int lines)
1253 Q_D(QDeclarative1Text);
1255 d->maximumLineCountValid = lines==INT_MAX ? false : true;
1256 if (d->maximumLineCount != lines) {
1257 d->maximumLineCount = lines;
1259 emit maximumLineCountChanged();
1263 void QDeclarative1Text::resetMaximumLineCount()
1265 Q_D(QDeclarative1Text);
1266 setMaximumLineCount(INT_MAX);
1267 d->elidePos = QPointF();
1268 if (d->truncated != false) {
1269 d->truncated = false;
1270 emit truncatedChanged();
1275 \qmlproperty enumeration QtQuick1::Text::textFormat
1277 The way the text property should be displayed.
1279 Supported text formats are:
1282 \o Text.AutoText (default)
1288 If the text format is \c Text.AutoText the text element
1289 will automatically determine whether the text should be treated as
1290 rich text. This determination is made using Qt::mightBeRichText().
1292 Text.StyledText is an optimized format supporting some basic text
1293 styling markup, in the style of html 3.2:
1296 <font size="4" color="#ff0000">font size and color</font>
1303 \c Text.StyledText parser is strict, requiring tags to be correctly nested.
1312 text: "<b>Hello</b> <i>World!</i>"
1316 textFormat: Text.RichText
1317 text: "<b>Hello</b> <i>World!</i>"
1321 textFormat: Text.PlainText
1322 text: "<b>Hello</b> <i>World!</i>"
1326 \o \image declarative-textformat.png
1329 QDeclarative1Text::TextFormat QDeclarative1Text::textFormat() const
1331 Q_D(const QDeclarative1Text);
1335 void QDeclarative1Text::setTextFormat(TextFormat format)
1337 Q_D(QDeclarative1Text);
1338 if (format == d->format)
1341 bool wasRich = d->richText;
1342 d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
1344 if (!wasRich && d->richText && isComponentComplete()) {
1346 d->doc->setText(d->text);
1351 emit textFormatChanged(d->format);
1355 \qmlproperty enumeration QtQuick1::Text::elide
1357 Set this property to elide parts of the text fit to the Text item's width.
1358 The text will only elide if an explicit width has been set.
1360 This property cannot be used with rich text.
1364 \o Text.ElideNone - the default
1370 If this property is set to Text.ElideRight, it can be used with multiline
1371 text. The text will only elide if maximumLineCount has been set.
1373 If the text is a multi-length string, and the mode is not \c Text.ElideNone,
1374 the first string that fits will be used, otherwise the last will be elided.
1376 Multi-length strings are ordered from longest to shortest, separated by the
1377 Unicode "String Terminator" character \c U009C (write this in QML with \c{"\u009C"} or \c{"\x9C"}).
1379 QDeclarative1Text::TextElideMode QDeclarative1Text::elideMode() const
1381 Q_D(const QDeclarative1Text);
1382 return d->elideMode;
1385 void QDeclarative1Text::setElideMode(QDeclarative1Text::TextElideMode mode)
1387 Q_D(QDeclarative1Text);
1388 if (mode == d->elideMode)
1391 d->elideMode = mode;
1394 emit elideModeChanged(d->elideMode);
1398 QRectF QDeclarative1Text::boundingRect() const
1400 Q_D(const QDeclarative1Text);
1402 QRect rect = d->layedOutTextRect;
1403 if (d->style != Normal)
1404 rect.adjust(-1, 0, 1, 2);
1406 // Could include font max left/right bearings to either side of rectangle.
1409 switch (d->vAlign) {
1413 rect.moveTop(h - rect.height());
1416 rect.moveTop((h - rect.height()) / 2);
1420 return QRectF(rect);
1424 void QDeclarative1Text::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
1426 Q_D(QDeclarative1Text);
1427 if ((!d->internalWidthUpdate && newGeometry.width() != oldGeometry.width())
1428 && (d->wrapMode != QDeclarative1Text::NoWrap
1429 || d->elideMode != QDeclarative1Text::ElideNone
1430 || d->hAlign != QDeclarative1Text::AlignLeft)) {
1431 if ((d->singleline || d->maximumLineCountValid) && d->elideMode != QDeclarative1Text::ElideNone && widthValid()) {
1432 // We need to re-elide
1435 // We just need to re-layout
1440 QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
1444 \qmlproperty real QtQuick1::Text::paintedWidth
1446 Returns the width of the text, including width past the width
1447 which is covered due to insufficient wrapping if WrapMode is set.
1449 qreal QDeclarative1Text::paintedWidth() const
1451 Q_D(const QDeclarative1Text);
1452 return d->paintedSize.width();
1456 \qmlproperty real QtQuick1::Text::paintedHeight
1458 Returns the height of the text, including height past the height
1459 which is covered due to there being more text than fits in the set height.
1461 qreal QDeclarative1Text::paintedHeight() const
1463 Q_D(const QDeclarative1Text);
1464 return d->paintedSize.height();
1468 \qmlproperty real QtQuick1::Text::lineHeight
1471 Sets the line height for the text.
1472 The value can be in pixels or a multiplier depending on lineHeightMode.
1474 The default value is a multiplier of 1.0.
1475 The line height must be a positive value.
1477 qreal QDeclarative1Text::lineHeight() const
1479 Q_D(const QDeclarative1Text);
1480 return d->lineHeight;
1483 void QDeclarative1Text::setLineHeight(qreal lineHeight)
1485 Q_D(QDeclarative1Text);
1487 if ((d->lineHeight == lineHeight) || (lineHeight < 0.0))
1490 d->lineHeight = lineHeight;
1492 emit lineHeightChanged(lineHeight);
1496 \qmlproperty enumeration QtQuick1::Text::lineHeightMode
1498 This property determines how the line height is specified.
1499 The possible values are:
1502 \o Text.ProportionalHeight (default) - this sets the spacing proportional to the
1503 line (as a multiplier). For example, set to 2 for double spacing.
1504 \o Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
1507 QDeclarative1Text::LineHeightMode QDeclarative1Text::lineHeightMode() const
1509 Q_D(const QDeclarative1Text);
1510 return d->lineHeightMode;
1513 void QDeclarative1Text::setLineHeightMode(LineHeightMode mode)
1515 Q_D(QDeclarative1Text);
1516 if (mode == d->lineHeightMode)
1519 d->lineHeightMode = mode;
1522 emit lineHeightModeChanged(mode);
1526 Returns the number of resources (images) that are being loaded asynchronously.
1528 int QDeclarative1Text::resourcesLoading() const
1530 Q_D(const QDeclarative1Text);
1531 return d->doc ? d->doc->resourcesLoading() : 0;
1535 void QDeclarative1Text::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
1537 Q_D(QDeclarative1Text);
1539 if (d->cacheAllTextAsImage || d->style != Normal) {
1540 d->checkImageCache();
1541 if (d->imageCache.isNull())
1544 bool oldAA = p->testRenderHint(QPainter::Antialiasing);
1545 bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform);
1547 p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth);
1549 QRect br = boundingRect().toRect();
1551 bool needClip = clip() && (d->imageCache.width() > width() ||
1552 d->imageCache.height() > height());
1555 p->drawPixmap(0, 0, width(), height(), d->imageCache, -br.x(), -br.y(), width(), height());
1557 p->drawPixmap(br.x(), br.y(), d->imageCache);
1560 p->setRenderHint(QPainter::Antialiasing, oldAA);
1561 p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth);
1564 QRectF bounds = boundingRect();
1566 bool needClip = clip() && (d->layedOutTextRect.width() > width() ||
1567 d->layedOutTextRect.height() > height());
1571 p->setClipRect(0, 0, width(), height(), Qt::IntersectClip);
1574 QAbstractTextDocumentLayout::PaintContext context;
1575 context.palette.setColor(QPalette::Text, d->color);
1576 p->translate(bounds.x(), bounds.y());
1577 d->doc->documentLayout()->draw(p, context);
1578 p->translate(-bounds.x(), -bounds.y());
1580 d->drawTextLayout(p, QPointF(0, bounds.y()), false);
1590 void QDeclarative1Text::componentComplete()
1592 Q_D(QDeclarative1Text);
1593 QDeclarativeItem::componentComplete();
1594 if (d->updateOnComponentComplete) {
1595 d->updateOnComponentComplete = false;
1598 d->doc->setText(d->text);
1599 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1601 d->rightToLeftText = d->text.isRightToLeft();
1603 d->determineHorizontalAlignment();
1609 void QDeclarative1Text::mousePressEvent(QGraphicsSceneMouseEvent *event)
1611 Q_D(QDeclarative1Text);
1613 if (!d->richText || !d->doc || d->doc->documentLayout()->anchorAt(event->pos()).isEmpty()) {
1614 event->setAccepted(false);
1615 d->activeLink.clear();
1617 d->activeLink = d->doc->documentLayout()->anchorAt(event->pos());
1620 // ### may malfunction if two of the same links are clicked & dragged onto each other)
1622 if (!event->isAccepted())
1623 QDeclarativeItem::mousePressEvent(event);
1628 void QDeclarative1Text::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1630 Q_D(QDeclarative1Text);
1632 // ### confirm the link, and send a signal out
1633 if (d->richText && d->doc && d->activeLink == d->doc->documentLayout()->anchorAt(event->pos()))
1634 emit linkActivated(d->activeLink);
1636 event->setAccepted(false);
1638 if (!event->isAccepted())
1639 QDeclarativeItem::mouseReleaseEvent(event);
1646 #include "qdeclarativetext.moc"