1 /****************************************************************************
3 ** Copyright (C) 2012 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>
55 #include <QtGui/QInputPanel>
63 extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
65 class QTextDocumentWithImageResources_1 : public QTextDocument {
69 QTextDocumentWithImageResources_1(QDeclarative1Text *parent);
70 virtual ~QTextDocumentWithImageResources_1();
72 void setText(const QString &);
73 int resourcesLoading() const { return outstanding; }
76 QVariant loadResource(int type, const QUrl &name);
79 void requestFinished();
82 QHash<QUrl, QDeclarative1Pixmap *> m_resources;
85 static QSet<QUrl> errors;
89 QTextDocumentWithImageResources_1::QTextDocumentWithImageResources_1(QDeclarative1Text *parent)
90 : QTextDocument(parent), outstanding(0)
94 QTextDocumentWithImageResources_1::~QTextDocumentWithImageResources_1()
96 if (!m_resources.isEmpty())
97 qDeleteAll(m_resources);
100 QVariant QTextDocumentWithImageResources_1::loadResource(int type, const QUrl &name)
102 QDeclarativeContext *context = qmlContext(parent());
103 QUrl url = context->resolvedUrl(name);
105 if (type == QTextDocument::ImageResource) {
106 QHash<QUrl, QDeclarative1Pixmap *>::Iterator iter = m_resources.find(url);
108 if (iter == m_resources.end()) {
109 QDeclarative1Pixmap *p = new QDeclarative1Pixmap(context->engine(), url);
110 iter = m_resources.insert(name, p);
112 if (p->isLoading()) {
113 p->connectFinished(this, SLOT(requestFinished()));
118 QDeclarative1Pixmap *p = *iter;
121 } else if (p->isError()) {
122 if (!errors.contains(url)) {
124 qmlInfo(parent()) << p->error();
129 return QTextDocument::loadResource(type,url); // The *resolved* URL
132 void QTextDocumentWithImageResources_1::requestFinished()
135 if (outstanding == 0) {
136 QDeclarative1Text *textItem = static_cast<QDeclarative1Text*>(parent());
137 QString text = textItem->text();
138 #ifndef QT_NO_TEXTHTMLPARSER
143 QDeclarative1TextPrivate *d = QDeclarative1TextPrivate::get(textItem);
148 void QTextDocumentWithImageResources_1::setText(const QString &text)
150 if (!m_resources.isEmpty()) {
151 qDeleteAll(m_resources);
156 #ifndef QT_NO_TEXTHTMLPARSER
163 QSet<QUrl> QTextDocumentWithImageResources_1::errors;
165 QDeclarative1TextPrivate::~QDeclarative1TextPrivate()
169 DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE);
171 QString QDeclarative1TextPrivate::elideChar = QString(0x2026);
173 QDeclarative1TextPrivate::QDeclarative1TextPrivate()
174 : color((QRgb)0), style(QDeclarative1Text::Normal), hAlign(QDeclarative1Text::AlignLeft),
175 vAlign(QDeclarative1Text::AlignTop), elideMode(QDeclarative1Text::ElideNone),
176 format(QDeclarative1Text::AutoText), wrapMode(QDeclarative1Text::NoWrap), lineHeight(1),
177 lineHeightMode(QDeclarative1Text::ProportionalHeight), lineCount(1), truncated(false), maximumLineCount(INT_MAX),
178 maximumLineCountValid(false), imageCacheDirty(true), updateOnComponentComplete(true), richText(false), singleline(false),
179 cacheAllTextAsImage(true), internalWidthUpdate(false), requireImplicitWidth(false), hAlignImplicit(true),
180 rightToLeftText(false), layoutTextElided(false), naturalWidth(0), doc(0)
182 cacheAllTextAsImage = enableImageCache();
183 QGraphicsItemPrivate::acceptedMouseButtons = Qt::LeftButton;
184 QGraphicsItemPrivate::flags = QGraphicsItemPrivate::flags & ~QGraphicsItem::ItemHasNoContents;
187 qreal QDeclarative1TextPrivate::implicitWidth() const
189 if (!requireImplicitWidth) {
190 // We don't calculate implicitWidth unless it is required.
191 // We need to force a size update now to ensure implicitWidth is calculated
192 QDeclarative1TextPrivate *me = const_cast<QDeclarative1TextPrivate*>(this);
193 me->requireImplicitWidth = true;
196 return mImplicitWidth;
199 void QDeclarative1TextPrivate::updateLayout()
201 Q_Q(QDeclarative1Text);
202 if (!q->isComponentComplete()) {
203 updateOnComponentComplete = true;
207 layoutTextElided = false;
208 // Setup instance of QTextLayout for all cases other than richtext
210 layout.clearLayout();
211 layout.setFont(font);
212 if (format != QDeclarative1Text::StyledText) {
214 tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
215 singleline = !tmp.contains(QChar::LineSeparator);
216 if (singleline && !maximumLineCountValid && elideMode != QDeclarative1Text::ElideNone && q->widthValid()) {
217 QFontMetrics fm(font);
218 tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width());
220 layoutTextElided = true;
223 emit q->truncatedChanged();
230 QDeclarative1StyledText::parse(text, layout);
237 void QDeclarative1TextPrivate::updateSize()
239 Q_Q(QDeclarative1Text);
241 if (!q->isComponentComplete()) {
242 updateOnComponentComplete = true;
246 if (!requireImplicitWidth) {
247 emit q->implicitWidthChanged();
248 // if the implicitWidth is used, then updateSize() has already been called (recursively)
249 if (requireImplicitWidth)
253 invalidateImageCache();
255 QFontMetrics fm(font);
256 if (text.isEmpty()) {
257 q->setImplicitWidth(0);
258 q->setImplicitHeight(fm.height());
259 paintedSize = QSize(0, fm.height());
260 emit q->paintedSizeChanged();
265 int dy = q->height();
268 //setup instance of QTextLayout for all cases other than richtext
270 QRect textRect = setupTextLayout();
271 if (layedOutTextRect.size() != textRect.size())
272 q->prepareGeometryChange();
273 layedOutTextRect = textRect;
274 size = textRect.size();
277 singleline = false; // richtext can't elide or be optimized for single-line case
279 doc->setDefaultFont(font);
281 QDeclarative1Text::HAlignment horizontalAlignment = q->effectiveHAlign();
282 if (rightToLeftText) {
283 if (horizontalAlignment == QDeclarative1Text::AlignLeft)
284 horizontalAlignment = QDeclarative1Text::AlignRight;
285 else if (horizontalAlignment == QDeclarative1Text::AlignRight)
286 horizontalAlignment = QDeclarative1Text::AlignLeft;
289 option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
290 option.setWrapMode(QTextOption::WrapMode(wrapMode));
291 doc->setDefaultTextOption(option);
292 if (requireImplicitWidth && q->widthValid()) {
293 doc->setTextWidth(-1);
294 naturalWidth = doc->idealWidth();
296 if (wrapMode != QDeclarative1Text::NoWrap && q->widthValid())
297 doc->setTextWidth(q->width());
299 doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
300 dy -= (int)doc->size().height();
301 QSize dsize = doc->size().toSize();
302 if (dsize != layedOutTextRect.size()) {
303 q->prepareGeometryChange();
304 layedOutTextRect = QRect(QPoint(0,0), dsize);
306 size = QSize(int(doc->idealWidth()),dsize.height());
310 if (q->heightValid()) {
311 if (vAlign == QDeclarative1Text::AlignBottom)
313 else if (vAlign == QDeclarative1Text::AlignVCenter)
316 q->setBaselineOffset(fm.ascent() + yoff);
318 //### need to comfirm cost of always setting these for richText
319 internalWidthUpdate = true;
320 if (!q->widthValid())
321 q->setImplicitWidth(size.width());
322 else if (requireImplicitWidth)
323 q->setImplicitWidth(naturalWidth);
324 internalWidthUpdate = false;
325 q->setImplicitHeight(size.height());
326 if (paintedSize != size) {
328 emit q->paintedSizeChanged();
334 Lays out the QDeclarative1TextPrivate::layout QTextLayout in the constraints of the QDeclarative1Text.
336 Returns the size of the final text. This can be used to position the text vertically (the text is
337 already absolutely positioned horizontally).
339 QRect QDeclarative1TextPrivate::setupTextLayout()
341 // ### text layout handling should be profiled and optimized as needed
342 // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
343 Q_Q(QDeclarative1Text);
344 layout.setCacheEnabled(true);
347 int visibleCount = 0;
351 lineWidth = q->width();
353 QTextOption textOption = layout.textOption();
354 textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
355 textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
356 layout.setTextOption(textOption);
358 bool elideText = false;
359 bool truncate = false;
361 QFontMetrics fm(layout.font());
362 elidePos = QPointF();
364 if (requireImplicitWidth && q->widthValid()) {
365 // requires an extra layout
367 if (layoutTextElided) {
368 // We have provided elided text to the layout, but we must calculate unelided width.
369 elidedText = layout.text();
370 layout.setText(text);
372 layout.beginLayout();
374 QTextLine line = layout.createLine();
380 for (int i = 0; i < layout.lineCount(); ++i) {
381 QTextLine line = layout.lineAt(i);
382 br = br.united(line.naturalTextRect());
384 naturalWidth = br.width();
385 if (layoutTextElided)
386 layout.setText(elidedText);
389 if (maximumLineCountValid) {
390 layout.beginLayout();
393 int linesLeft = maximumLineCount;
394 int visibleTextLength = 0;
395 while (linesLeft > 0) {
396 QTextLine line = layout.createLine();
402 line.setLineWidth(lineWidth);
403 visibleTextLength += line.textLength();
405 if (--linesLeft == 0) {
406 if (visibleTextLength < text.length()) {
408 if (elideMode==QDeclarative1Text::ElideRight && q->widthValid()) {
409 qreal elideWidth = fm.width(elideChar);
410 // Need to correct for alignment
411 line.setLineWidth(lineWidth-elideWidth);
412 if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) {
413 line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y()));
414 elidePos.setX(line.naturalTextRect().left() - elideWidth);
416 elidePos.setX(line.naturalTextRect().right());
426 if (truncated != truncate) {
427 truncated = truncate;
428 emit q->truncatedChanged();
431 layout.beginLayout();
433 QTextLine line = layout.createLine();
438 line.setLineWidth(lineWidth);
445 for (int i = 0; i < layout.lineCount(); ++i) {
446 QTextLine line = layout.lineAt(i);
448 line.setPosition(QPointF(line.position().x(), height));
449 if (elideText && i == layout.lineCount()-1) {
450 elidePos.setY(height + fm.ascent());
451 br = br.united(QRectF(elidePos, QSizeF(fm.width(elideChar), fm.ascent())));
453 br = br.united(line.naturalTextRect());
454 height += (lineHeightMode == QDeclarative1Text::FixedHeight) ? lineHeight : line.height() * lineHeight;
456 br.setHeight(height);
458 if (!q->widthValid())
459 naturalWidth = br.width();
461 //Update the number of visible lines
462 if (lineCount != visibleCount) {
463 lineCount = visibleCount;
464 emit q->lineCountChanged();
467 return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height()));
471 Returns a painted version of the QDeclarative1TextPrivate::layout QTextLayout.
472 If \a drawStyle is true, the style color overrides all colors in the document.
474 QPixmap QDeclarative1TextPrivate::textLayoutImage(bool drawStyle)
477 QSize size = layedOutTextRect.size();
480 if (!size.isEmpty()) {
481 img.fill(Qt::transparent);
483 bool oldSmooth = qt_applefontsmoothing_enabled;
484 qt_applefontsmoothing_enabled = false;
488 qt_applefontsmoothing_enabled = oldSmooth;
490 drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle);
496 Paints the QDeclarative1TextPrivate::layout QTextLayout into \a painter at \a pos. If
497 \a drawStyle is true, the style color overrides all colors in the document.
499 void QDeclarative1TextPrivate::drawTextLayout(QPainter *painter, const QPointF &pos, bool drawStyle)
502 painter->setPen(styleColor);
504 painter->setPen(color);
505 painter->setFont(font);
506 layout.draw(painter, pos);
507 if (!elidePos.isNull())
508 painter->drawText(pos + elidePos, elideChar);
512 Returns a painted version of the QDeclarative1TextPrivate::doc QTextDocument.
513 If \a drawStyle is true, the style color overrides all colors in the document.
515 QPixmap QDeclarative1TextPrivate::textDocumentImage(bool drawStyle)
517 QSize size = doc->size().toSize();
521 img.fill(Qt::transparent);
523 bool oldSmooth = qt_applefontsmoothing_enabled;
524 qt_applefontsmoothing_enabled = false;
528 qt_applefontsmoothing_enabled = oldSmooth;
531 QAbstractTextDocumentLayout::PaintContext context;
533 QTextOption oldOption(doc->defaultTextOption());
535 context.palette.setColor(QPalette::Text, styleColor);
536 QTextOption colorOption(doc->defaultTextOption());
537 colorOption.setFlags(QTextOption::SuppressColors);
538 doc->setDefaultTextOption(colorOption);
540 context.palette.setColor(QPalette::Text, color);
542 doc->documentLayout()->draw(&p, context);
544 doc->setDefaultTextOption(oldOption);
549 Mark the image cache as dirty.
551 void QDeclarative1TextPrivate::invalidateImageCache()
553 Q_Q(QDeclarative1Text);
555 if(cacheAllTextAsImage || style != QDeclarative1Text::Normal){//If actually using the image cache
559 imageCacheDirty = true;
560 imageCache = QPixmap();
562 if (q->isComponentComplete())
567 Tests if the image cache is dirty, and repaints it if it is.
569 void QDeclarative1TextPrivate::checkImageCache()
571 if (!imageCacheDirty)
574 if (text.isEmpty()) {
576 imageCache = QPixmap();
584 textImage = textDocumentImage(false);
585 if (style != QDeclarative1Text::Normal)
586 styledImage = textDocumentImage(true); //### should use styleColor
588 textImage = textLayoutImage(false);
589 if (style != QDeclarative1Text::Normal)
590 styledImage = textLayoutImage(true); //### should use styleColor
594 case QDeclarative1Text::Outline:
595 imageCache = drawOutline(textImage, styledImage);
597 case QDeclarative1Text::Sunken:
598 imageCache = drawOutline(textImage, styledImage, -1);
600 case QDeclarative1Text::Raised:
601 imageCache = drawOutline(textImage, styledImage, 1);
604 imageCache = textImage;
610 imageCacheDirty = false;
614 Ensures the QDeclarative1TextPrivate::doc variable is set to a valid text document
616 void QDeclarative1TextPrivate::ensureDoc()
619 Q_Q(QDeclarative1Text);
620 doc = new QTextDocumentWithImageResources_1(q);
621 doc->setDocumentMargin(0);
626 Draw \a styleSource as an outline around \a source and return the new image.
628 QPixmap QDeclarative1TextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource)
630 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
631 img.fill(Qt::transparent);
636 pos += QPoint(-1, 0);
637 ppm.drawPixmap(pos, styleSource);
639 ppm.drawPixmap(pos, styleSource);
640 pos += QPoint(-1, -1);
641 ppm.drawPixmap(pos, styleSource);
643 ppm.drawPixmap(pos, styleSource);
645 pos += QPoint(0, -1);
646 ppm.drawPixmap(pos, source);
653 Draw \a styleSource below \a source at \a yOffset and return the new image.
655 QPixmap QDeclarative1TextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset)
657 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
658 img.fill(Qt::transparent);
662 ppm.drawPixmap(QPoint(0, yOffset), styleSource);
663 ppm.drawPixmap(0, 0, source);
671 \qmlclass Text QDeclarative1Text
672 \inqmlmodule QtQuick 1
673 \ingroup qml-basic-visual-elements
675 \brief The Text item allows you to add formatted text to a scene.
678 Text items can display both plain and rich text. For example, red text with
679 a specific font and size can be defined like this:
684 font.family: "Helvetica"
690 Rich text is defined using HTML-style markup:
694 text: "<b>Hello</b> <i>World!</i>"
698 \image declarative-text.png
700 If height and width are not explicitly set, Text will attempt to determine how
701 much room is needed and set it accordingly. Unless \l wrapMode is set, it will always
702 prefer width to height (all text will be placed on a single line).
704 The \l elide property can alternatively be used to fit a single line of
705 plain text to a set width.
707 Note that the \l{Supported HTML Subset} is limited. Also, if the text contains
708 HTML img tags that load remote images, the text is reloaded.
710 Text provides read-only text. For editable text, see \l TextEdit.
712 \sa {declarative/text/fonts}{Fonts example}
714 QDeclarative1Text::QDeclarative1Text(QDeclarativeItem *parent)
715 : QDeclarative1ImplicitSizeItem(*(new QDeclarative1TextPrivate), parent)
719 QDeclarative1Text::~QDeclarative1Text()
724 \qmlproperty bool QtQuick1::Text::clip
725 This property holds whether the text is clipped.
727 Note that if the text does not fit in the bounding rectangle it will be abruptly chopped.
729 If you want to display potentially long text in a limited space, you probably want to use \c elide instead.
733 \qmlproperty bool QtQuick1::Text::smooth
735 This property holds whether the text is smoothly scaled or transformed.
737 Smooth filtering gives better visual quality, but is slower. If
738 the item is displayed at its natural size, this property has no visual or
741 \note Generally scaling artifacts are only visible if the item is stationary on
742 the screen. A common pattern when animating an item is to disable smooth
743 filtering at the beginning of the animation and reenable it at the conclusion.
747 \qmlsignal QtQuick1::Text::onLinkActivated(string link)
749 This handler is called when the user clicks on a link embedded in the text.
750 The link must be in rich text or HTML format and the
751 \a link string provides access to the particular link.
753 \snippet doc/src/snippets/qtquick1/text/onLinkActivated.qml 0
755 The example code will display the text
756 "The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}."
758 Clicking on the highlighted link will output
759 \tt{http://qt.nokia.com link activated} to the console.
763 \qmlproperty string QtQuick1::Text::font.family
765 Sets the family name of the font.
767 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
768 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
769 If the family isn't available a family will be set using the font matching algorithm.
773 \qmlproperty bool QtQuick1::Text::font.bold
775 Sets whether the font weight is bold.
779 \qmlproperty enumeration QtQuick1::Text::font.weight
781 Sets the font's weight.
783 The weight can be one of:
786 \o Font.Normal - the default
793 Text { text: "Hello"; font.weight: Font.DemiBold }
798 \qmlproperty bool QtQuick1::Text::font.italic
800 Sets whether the font has an italic style.
804 \qmlproperty bool QtQuick1::Text::font.underline
806 Sets whether the text is underlined.
810 \qmlproperty bool QtQuick1::Text::font.strikeout
812 Sets whether the font has a strikeout style.
816 \qmlproperty real QtQuick1::Text::font.pointSize
818 Sets the font size in points. The point size must be greater than zero.
822 \qmlproperty int QtQuick1::Text::font.pixelSize
824 Sets the font size in pixels.
826 Using this function makes the font device dependent.
827 Use \c pointSize to set the size of the font in a device independent manner.
831 \qmlproperty real QtQuick1::Text::font.letterSpacing
833 Sets the letter spacing for the font.
835 Letter spacing changes the default spacing between individual letters in the font.
836 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
840 \qmlproperty real QtQuick1::Text::font.wordSpacing
842 Sets the word spacing for the font.
844 Word spacing changes the default spacing between individual words.
845 A positive value increases the word spacing by a corresponding amount of pixels,
846 while a negative value decreases the inter-word spacing accordingly.
850 \qmlproperty enumeration QtQuick1::Text::font.capitalization
852 Sets the capitalization for the text.
855 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
856 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
857 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
858 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
859 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
863 Text { text: "Hello"; font.capitalization: Font.AllLowercase }
866 QFont QDeclarative1Text::font() const
868 Q_D(const QDeclarative1Text);
869 return d->sourceFont;
872 void QDeclarative1Text::setFont(const QFont &font)
874 Q_D(QDeclarative1Text);
875 if (d->sourceFont == font)
878 d->sourceFont = font;
879 QFont oldFont = d->font;
881 if (d->font.pointSizeF() != -1) {
883 qreal size = qRound(d->font.pointSizeF()*2.0);
884 d->font.setPointSizeF(size/2.0);
887 if (oldFont != d->font)
890 emit fontChanged(d->sourceFont);
894 \qmlproperty string QtQuick1::Text::text
896 The text to display. Text supports both plain and rich text strings.
898 The item will try to automatically determine whether the text should
899 be treated as rich text. This determination is made using Qt::mightBeRichText().
901 QString QDeclarative1Text::text() const
903 Q_D(const QDeclarative1Text);
907 void QDeclarative1Text::setText(const QString &n)
909 Q_D(QDeclarative1Text);
913 d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n));
915 if (isComponentComplete()) {
919 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
921 d->rightToLeftText = d->text.isRightToLeft();
923 d->determineHorizontalAlignment();
926 emit textChanged(d->text);
931 \qmlproperty color QtQuick1::Text::color
935 An example of green text defined using hexadecimal notation:
943 An example of steel blue text defined using an SVG color name:
951 QColor QDeclarative1Text::color() const
953 Q_D(const QDeclarative1Text);
957 void QDeclarative1Text::setColor(const QColor &color)
959 Q_D(QDeclarative1Text);
960 if (d->color == color)
964 d->invalidateImageCache();
965 emit colorChanged(d->color);
969 \qmlproperty enumeration QtQuick1::Text::style
971 Set an additional text style.
973 Supported text styles are:
975 \o Text.Normal - the default
983 Text { font.pointSize: 24; text: "Normal" }
984 Text { font.pointSize: 24; text: "Raised"; style: Text.Raised; styleColor: "#AAAAAA" }
985 Text { font.pointSize: 24; text: "Outline";style: Text.Outline; styleColor: "red" }
986 Text { font.pointSize: 24; text: "Sunken"; style: Text.Sunken; styleColor: "#AAAAAA" }
990 \image declarative-textstyle.png
992 QDeclarative1Text::TextStyle QDeclarative1Text::style() const
994 Q_D(const QDeclarative1Text);
998 void QDeclarative1Text::setStyle(QDeclarative1Text::TextStyle style)
1000 Q_D(QDeclarative1Text);
1001 if (d->style == style)
1004 // changing to/from Normal requires the boundingRect() to change
1005 if (isComponentComplete() && (d->style == Normal || style == Normal))
1006 prepareGeometryChange();
1008 d->invalidateImageCache();
1009 emit styleChanged(d->style);
1013 \qmlproperty color QtQuick1::Text::styleColor
1015 Defines the secondary color used by text styles.
1017 \c styleColor is used as the outline color for outlined text, and as the
1018 shadow color for raised or sunken text. If no style has been set, it is not
1022 Text { font.pointSize: 18; text: "hello"; style: Text.Raised; styleColor: "gray" }
1027 QColor QDeclarative1Text::styleColor() const
1029 Q_D(const QDeclarative1Text);
1030 return d->styleColor;
1033 void QDeclarative1Text::setStyleColor(const QColor &color)
1035 Q_D(QDeclarative1Text);
1036 if (d->styleColor == color)
1039 d->styleColor = color;
1040 d->invalidateImageCache();
1041 emit styleColorChanged(d->styleColor);
1046 \qmlproperty enumeration QtQuick1::Text::horizontalAlignment
1047 \qmlproperty enumeration QtQuick1::Text::verticalAlignment
1048 \qmlproperty enumeration QtQuick1::Text::effectiveHorizontalAlignment
1050 Sets the horizontal and vertical alignment of the text within the Text items
1051 width and height. By default, the text is vertically aligned to the top. Horizontal
1052 alignment follows the natural alignment of the text, for example text that is read
1053 from left to right will be aligned to the left.
1055 The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and
1056 \c Text.AlignJustify. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom
1057 and \c Text.AlignVCenter.
1059 Note that for a single line of text, the size of the text is the area of the text. In this common case,
1060 all alignments are equivalent. If you want the text to be, say, centered in its parent, then you will
1061 need to either modify the Item::anchors, or set horizontalAlignment to Text.AlignHCenter and bind the width to
1064 When using the attached property LayoutMirroring::enabled to mirror application
1065 layouts, the horizontal alignment of text will also be mirrored. However, the property
1066 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
1067 of Text, use the read-only property \c effectiveHorizontalAlignment.
1069 QDeclarative1Text::HAlignment QDeclarative1Text::hAlign() const
1071 Q_D(const QDeclarative1Text);
1075 void QDeclarative1Text::setHAlign(HAlignment align)
1077 Q_D(QDeclarative1Text);
1078 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
1079 d->hAlignImplicit = false;
1080 if (d->setHAlign(align, forceAlign) && isComponentComplete())
1084 void QDeclarative1Text::resetHAlign()
1086 Q_D(QDeclarative1Text);
1087 d->hAlignImplicit = true;
1088 if (d->determineHorizontalAlignment() && isComponentComplete())
1092 QDeclarative1Text::HAlignment QDeclarative1Text::effectiveHAlign() const
1094 Q_D(const QDeclarative1Text);
1095 QDeclarative1Text::HAlignment effectiveAlignment = d->hAlign;
1096 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
1097 switch (d->hAlign) {
1098 case QDeclarative1Text::AlignLeft:
1099 effectiveAlignment = QDeclarative1Text::AlignRight;
1101 case QDeclarative1Text::AlignRight:
1102 effectiveAlignment = QDeclarative1Text::AlignLeft;
1108 return effectiveAlignment;
1111 bool QDeclarative1TextPrivate::setHAlign(QDeclarative1Text::HAlignment alignment, bool forceAlign)
1113 Q_Q(QDeclarative1Text);
1114 if (hAlign != alignment || forceAlign) {
1115 QDeclarative1Text::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
1118 emit q->horizontalAlignmentChanged(hAlign);
1119 if (oldEffectiveHAlign != q->effectiveHAlign())
1120 emit q->effectiveHorizontalAlignmentChanged();
1126 bool QDeclarative1TextPrivate::determineHorizontalAlignment()
1128 Q_Q(QDeclarative1Text);
1129 if (hAlignImplicit && q->isComponentComplete()) {
1130 bool alignToRight = text.isEmpty() ? qApp->inputPanel()->inputDirection() == Qt::RightToLeft : rightToLeftText;
1131 return setHAlign(alignToRight ? QDeclarative1Text::AlignRight : QDeclarative1Text::AlignLeft);
1136 void QDeclarative1TextPrivate::mirrorChange()
1138 Q_Q(QDeclarative1Text);
1139 if (q->isComponentComplete()) {
1140 if (!hAlignImplicit && (hAlign == QDeclarative1Text::AlignRight || hAlign == QDeclarative1Text::AlignLeft)) {
1142 emit q->effectiveHorizontalAlignmentChanged();
1147 QTextDocument *QDeclarative1TextPrivate::textDocument()
1152 QDeclarative1Text::VAlignment QDeclarative1Text::vAlign() const
1154 Q_D(const QDeclarative1Text);
1158 void QDeclarative1Text::setVAlign(VAlignment align)
1160 Q_D(QDeclarative1Text);
1161 if (d->vAlign == align)
1164 if (isComponentComplete())
1165 prepareGeometryChange();
1167 emit verticalAlignmentChanged(align);
1171 \qmlproperty enumeration QtQuick1::Text::wrapMode
1173 Set this property to wrap the text to the Text item's width. The text will only
1174 wrap if an explicit width has been set. wrapMode can be one of:
1177 \o Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l paintedWidth will exceed a set width.
1178 \o Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l paintedWidth will exceed a set width.
1179 \o Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
1180 \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.
1183 QDeclarative1Text::WrapMode QDeclarative1Text::wrapMode() const
1185 Q_D(const QDeclarative1Text);
1189 void QDeclarative1Text::setWrapMode(WrapMode mode)
1191 Q_D(QDeclarative1Text);
1192 if (mode == d->wrapMode)
1198 emit wrapModeChanged();
1202 \qmlproperty int QtQuick1::Text::lineCount
1205 Returns the number of lines visible in the text item.
1207 This property is not supported for rich text.
1209 \sa maximumLineCount
1211 int QDeclarative1Text::lineCount() const
1213 Q_D(const QDeclarative1Text);
1214 return d->lineCount;
1218 \qmlproperty bool QtQuick1::Text::truncated
1221 Returns true if the text has been truncated due to \l maximumLineCount
1224 This property is not supported for rich text.
1226 \sa maximumLineCount, elide
1228 bool QDeclarative1Text::truncated() const
1230 Q_D(const QDeclarative1Text);
1231 return d->truncated;
1235 \qmlproperty int QtQuick1::Text::maximumLineCount
1238 Set this property to limit the number of lines that the text item will show.
1239 If elide is set to Text.ElideRight, the text will be elided appropriately.
1240 By default, this is the value of the largest possible integer.
1242 This property is not supported for rich text.
1244 \sa lineCount, elide
1246 int QDeclarative1Text::maximumLineCount() const
1248 Q_D(const QDeclarative1Text);
1249 return d->maximumLineCount;
1252 void QDeclarative1Text::setMaximumLineCount(int lines)
1254 Q_D(QDeclarative1Text);
1256 d->maximumLineCountValid = lines==INT_MAX ? false : true;
1257 if (d->maximumLineCount != lines) {
1258 d->maximumLineCount = lines;
1260 emit maximumLineCountChanged();
1264 void QDeclarative1Text::resetMaximumLineCount()
1266 Q_D(QDeclarative1Text);
1267 setMaximumLineCount(INT_MAX);
1268 d->elidePos = QPointF();
1269 if (d->truncated != false) {
1270 d->truncated = false;
1271 emit truncatedChanged();
1276 \qmlproperty enumeration QtQuick1::Text::textFormat
1278 The way the text property should be displayed.
1280 Supported text formats are:
1283 \o Text.AutoText (default)
1289 If the text format is \c Text.AutoText the text element
1290 will automatically determine whether the text should be treated as
1291 rich text. This determination is made using Qt::mightBeRichText().
1293 Text.StyledText is an optimized format supporting some basic text
1294 styling markup, in the style of html 3.2:
1297 <font size="4" color="#ff0000">font size and color</font>
1304 \c Text.StyledText parser is strict, requiring tags to be correctly nested.
1313 text: "<b>Hello</b> <i>World!</i>"
1317 textFormat: Text.RichText
1318 text: "<b>Hello</b> <i>World!</i>"
1322 textFormat: Text.PlainText
1323 text: "<b>Hello</b> <i>World!</i>"
1327 \o \image declarative-textformat.png
1330 QDeclarative1Text::TextFormat QDeclarative1Text::textFormat() const
1332 Q_D(const QDeclarative1Text);
1336 void QDeclarative1Text::setTextFormat(TextFormat format)
1338 Q_D(QDeclarative1Text);
1339 if (format == d->format)
1342 bool wasRich = d->richText;
1343 d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
1345 if (!wasRich && d->richText && isComponentComplete()) {
1347 d->doc->setText(d->text);
1352 emit textFormatChanged(d->format);
1356 \qmlproperty enumeration QtQuick1::Text::elide
1358 Set this property to elide parts of the text fit to the Text item's width.
1359 The text will only elide if an explicit width has been set.
1361 This property cannot be used with rich text.
1365 \o Text.ElideNone - the default
1371 If this property is set to Text.ElideRight, it can be used with multiline
1372 text. The text will only elide if maximumLineCount has been set.
1374 If the text is a multi-length string, and the mode is not \c Text.ElideNone,
1375 the first string that fits will be used, otherwise the last will be elided.
1377 Multi-length strings are ordered from longest to shortest, separated by the
1378 Unicode "String Terminator" character \c U009C (write this in QML with \c{"\u009C"} or \c{"\x9C"}).
1380 QDeclarative1Text::TextElideMode QDeclarative1Text::elideMode() const
1382 Q_D(const QDeclarative1Text);
1383 return d->elideMode;
1386 void QDeclarative1Text::setElideMode(QDeclarative1Text::TextElideMode mode)
1388 Q_D(QDeclarative1Text);
1389 if (mode == d->elideMode)
1392 d->elideMode = mode;
1395 emit elideModeChanged(d->elideMode);
1399 QRectF QDeclarative1Text::boundingRect() const
1401 Q_D(const QDeclarative1Text);
1403 QRect rect = d->layedOutTextRect;
1404 if (d->style != Normal)
1405 rect.adjust(-1, 0, 1, 2);
1407 // Could include font max left/right bearings to either side of rectangle.
1410 switch (d->vAlign) {
1414 rect.moveTop(h - rect.height());
1417 rect.moveTop((h - rect.height()) / 2);
1421 return QRectF(rect);
1425 void QDeclarative1Text::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
1427 Q_D(QDeclarative1Text);
1428 if ((!d->internalWidthUpdate && newGeometry.width() != oldGeometry.width())
1429 && (d->wrapMode != QDeclarative1Text::NoWrap
1430 || d->elideMode != QDeclarative1Text::ElideNone
1431 || d->hAlign != QDeclarative1Text::AlignLeft)) {
1432 if ((d->singleline || d->maximumLineCountValid) && d->elideMode != QDeclarative1Text::ElideNone && widthValid()) {
1433 // We need to re-elide
1436 // We just need to re-layout
1441 QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
1445 \qmlproperty real QtQuick1::Text::paintedWidth
1447 Returns the width of the text, including width past the width
1448 which is covered due to insufficient wrapping if WrapMode is set.
1450 qreal QDeclarative1Text::paintedWidth() const
1452 Q_D(const QDeclarative1Text);
1453 return d->paintedSize.width();
1457 \qmlproperty real QtQuick1::Text::paintedHeight
1459 Returns the height of the text, including height past the height
1460 which is covered due to there being more text than fits in the set height.
1462 qreal QDeclarative1Text::paintedHeight() const
1464 Q_D(const QDeclarative1Text);
1465 return d->paintedSize.height();
1469 \qmlproperty real QtQuick1::Text::lineHeight
1472 Sets the line height for the text.
1473 The value can be in pixels or a multiplier depending on lineHeightMode.
1475 The default value is a multiplier of 1.0.
1476 The line height must be a positive value.
1478 qreal QDeclarative1Text::lineHeight() const
1480 Q_D(const QDeclarative1Text);
1481 return d->lineHeight;
1484 void QDeclarative1Text::setLineHeight(qreal lineHeight)
1486 Q_D(QDeclarative1Text);
1488 if ((d->lineHeight == lineHeight) || (lineHeight < 0.0))
1491 d->lineHeight = lineHeight;
1493 emit lineHeightChanged(lineHeight);
1497 \qmlproperty enumeration QtQuick1::Text::lineHeightMode
1499 This property determines how the line height is specified.
1500 The possible values are:
1503 \o Text.ProportionalHeight (default) - this sets the spacing proportional to the
1504 line (as a multiplier). For example, set to 2 for double spacing.
1505 \o Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
1508 QDeclarative1Text::LineHeightMode QDeclarative1Text::lineHeightMode() const
1510 Q_D(const QDeclarative1Text);
1511 return d->lineHeightMode;
1514 void QDeclarative1Text::setLineHeightMode(LineHeightMode mode)
1516 Q_D(QDeclarative1Text);
1517 if (mode == d->lineHeightMode)
1520 d->lineHeightMode = mode;
1523 emit lineHeightModeChanged(mode);
1527 Returns the number of resources (images) that are being loaded asynchronously.
1529 int QDeclarative1Text::resourcesLoading() const
1531 Q_D(const QDeclarative1Text);
1532 return d->doc ? d->doc->resourcesLoading() : 0;
1536 void QDeclarative1Text::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
1538 Q_D(QDeclarative1Text);
1540 if (d->cacheAllTextAsImage || d->style != Normal) {
1541 d->checkImageCache();
1542 if (d->imageCache.isNull())
1545 bool oldAA = p->testRenderHint(QPainter::Antialiasing);
1546 bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform);
1548 p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth);
1550 QRect br = boundingRect().toRect();
1552 bool needClip = clip() && (d->imageCache.width() > width() ||
1553 d->imageCache.height() > height());
1556 p->drawPixmap(0, 0, width(), height(), d->imageCache, -br.x(), -br.y(), width(), height());
1558 p->drawPixmap(br.x(), br.y(), d->imageCache);
1561 p->setRenderHint(QPainter::Antialiasing, oldAA);
1562 p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth);
1565 QRectF bounds = boundingRect();
1567 bool needClip = clip() && (d->layedOutTextRect.width() > width() ||
1568 d->layedOutTextRect.height() > height());
1572 p->setClipRect(0, 0, width(), height(), Qt::IntersectClip);
1575 QAbstractTextDocumentLayout::PaintContext context;
1576 context.palette.setColor(QPalette::Text, d->color);
1577 p->translate(bounds.x(), bounds.y());
1578 d->doc->documentLayout()->draw(p, context);
1579 p->translate(-bounds.x(), -bounds.y());
1581 d->drawTextLayout(p, QPointF(0, bounds.y()), false);
1591 void QDeclarative1Text::componentComplete()
1593 Q_D(QDeclarative1Text);
1594 QDeclarativeItem::componentComplete();
1595 if (d->updateOnComponentComplete) {
1596 d->updateOnComponentComplete = false;
1599 d->doc->setText(d->text);
1600 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1602 d->rightToLeftText = d->text.isRightToLeft();
1604 d->determineHorizontalAlignment();
1610 void QDeclarative1Text::mousePressEvent(QGraphicsSceneMouseEvent *event)
1612 Q_D(QDeclarative1Text);
1614 if (!d->richText || !d->doc || d->doc->documentLayout()->anchorAt(event->pos()).isEmpty()) {
1615 event->setAccepted(false);
1616 d->activeLink.clear();
1618 d->activeLink = d->doc->documentLayout()->anchorAt(event->pos());
1621 // ### may malfunction if two of the same links are clicked & dragged onto each other)
1623 if (!event->isAccepted())
1624 QDeclarativeItem::mousePressEvent(event);
1629 void QDeclarative1Text::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1631 Q_D(QDeclarative1Text);
1633 // ### confirm the link, and send a signal out
1634 if (d->richText && d->doc && d->activeLink == d->doc->documentLayout()->anchorAt(event->pos()))
1635 emit linkActivated(d->activeLink);
1637 event->setAccepted(false);
1639 if (!event->isAccepted())
1640 QDeclarativeItem::mouseReleaseEvent(event);
1647 #include "qdeclarativetext.moc"