From 6fcaca378b84ada546dc62d72a53a71d0da86ef9 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Thu, 22 Sep 2011 11:34:58 +1000 Subject: [PATCH] Improvements to text layouting in QML Allow more control over the text layouting process in QML. Give access to every text line through a hook, this gives the opportunity to position and resize a line as it is being laid out. It is then possible to lay out the text in columns or around other objects. Task-number: QTBUG-21367 Change-Id: I56dc0c1c4b575dc06360c135098024d0324d3656 Reviewed-on: http://codereview.qt-project.org/5351 Reviewed-by: Yann Bodson Sanity-Review: Yann Bodson --- doc/src/declarative/whatsnew.qdoc | 7 +- src/declarative/items/qsgitemsmodule.cpp | 1 + src/declarative/items/qsgtext.cpp | 199 +++++++++++++++++++-- src/declarative/items/qsgtext_p.h | 37 ++++ src/declarative/items/qsgtext_p_p.h | 6 + tests/auto/declarative/qsgtext/data/lineLayout.qml | 35 ++++ tests/auto/declarative/qsgtext/tst_qsgtext.cpp | 29 ++- .../textlayout/styledtext-layout.qml | 109 +++++++++++ 8 files changed, 406 insertions(+), 17 deletions(-) create mode 100644 tests/auto/declarative/qsgtext/data/lineLayout.qml create mode 100644 tests/testapplications/textlayout/styledtext-layout.qml diff --git a/doc/src/declarative/whatsnew.qdoc b/doc/src/declarative/whatsnew.qdoc index 4efe0da..84245a5 100644 --- a/doc/src/declarative/whatsnew.qdoc +++ b/doc/src/declarative/whatsnew.qdoc @@ -99,8 +99,6 @@ Added topMargin, bottomMargin, leftMargin, rightMargin, xOrigin, yOrigin propert Image has two new properties: horizontalAlignment and verticalAlignment. It also has a new value for fillMode (Image.Pad) that does not transform the image. -Text will now automatically switch to StyledText instead of RichText if textFormat is set to AutoText. - Grid now has rowSpacing and columnSpacing properties. Positioners now have attached properties that can be used to determine a subitem's location within a @@ -112,6 +110,11 @@ Loader improvements: - now only emits the \c sourceChanged signal when the source is changed and the \c sourceComponentChanged signal when the sourceComponent is changed. It used to emit both signals when one of the properties was changed. +Text improvements: + - a \c onLineLaidOut handler is called for every line during the layout process. This gives the opportunity to position and resize a line as it is being laid out. + - a \c doLayout method was added to trigger the layout from Javascript. + - now automatically switch to StyledText instead of RichText if textFormat is set to AutoText. + PathView now has a \c currentItem property ListView and GridView now have headerItem and footerItem properties (the instantiated diff --git a/src/declarative/items/qsgitemsmodule.cpp b/src/declarative/items/qsgitemsmodule.cpp index 70a9499..5a99ef7 100644 --- a/src/declarative/items/qsgitemsmodule.cpp +++ b/src/declarative/items/qsgitemsmodule.cpp @@ -159,6 +159,7 @@ static void qt_sgitems_defineModule(const char *uri, int major, int minor) qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); + qmlRegisterType(); #ifndef QT_NO_VALIDATOR qmlRegisterType(); #endif diff --git a/src/declarative/items/qsgtext.cpp b/src/declarative/items/qsgtext.cpp index 735adb7..3c525c0 100644 --- a/src/declarative/items/qsgtext.cpp +++ b/src/declarative/items/qsgtext.cpp @@ -106,11 +106,11 @@ QSGTextPrivate::QSGTextPrivate() imageCacheDirty(false), updateOnComponentComplete(true), richText(false), styledText(false), singleline(false), cacheAllTextAsImage(true), internalWidthUpdate(false), requireImplicitWidth(false), truncated(false), hAlignImplicit(true), rightToLeftText(false), - layoutTextElided(false), richTextAsImage(false), textureImageCacheDirty(false), naturalWidth(0), - doc(0), nodeType(NodeIsNull) + layoutTextElided(false), richTextAsImage(false), textureImageCacheDirty(false), textHasChanged(true), + naturalWidth(0), doc(0), textLine(0), nodeType(NodeIsNull) #if defined(Q_OS_MAC) - , layoutThread(0) +, layoutThread(0), paintingThread(0) #endif { @@ -203,6 +203,7 @@ QSet QSGTextDocumentWithImageResources::errors; QSGTextPrivate::~QSGTextPrivate() { + delete textLine; textLine = 0; } qreal QSGTextPrivate::getImplicitWidth() const @@ -248,7 +249,10 @@ void QSGTextPrivate::updateLayout() layout.setText(tmp); } else { singleline = false; - QDeclarativeStyledText::parse(text, layout); + if (textHasChanged) { + QDeclarativeStyledText::parse(text, layout); + textHasChanged = false; + } } } else { ensureDoc(); @@ -362,6 +366,157 @@ void QSGTextPrivate::updateSize() q->update(); } +QSGTextLine::QSGTextLine() + : QObject(), m_line(0), m_height(0) +{ +} + +void QSGTextLine::setLine(QTextLine *line) +{ + m_line = line; +} + +int QSGTextLine::number() const +{ + if (m_line) + return m_line->lineNumber(); + return 0; +} + +qreal QSGTextLine::width() const +{ + if (m_line) + return m_line->width(); + return 0; +} + +void QSGTextLine::setWidth(qreal width) +{ + if (m_line) + m_line->setLineWidth(width); +} + +qreal QSGTextLine::height() const +{ + if (m_height) + return m_height; + if (m_line) + return m_line->height(); + return 0; +} + +void QSGTextLine::setHeight(qreal height) +{ + if (m_line) + m_line->setPosition(QPointF(m_line->x(), m_line->y() - m_line->height() + height)); + m_height = height; +} + +qreal QSGTextLine::x() const +{ + if (m_line) + return m_line->x(); + return 0; +} + +void QSGTextLine::setX(qreal x) +{ + if (m_line) + m_line->setPosition(QPointF(x, m_line->y())); +} + +qreal QSGTextLine::y() const +{ + if (m_line) + return m_line->y(); + return 0; +} + +void QSGTextLine::setY(qreal y) +{ + if (m_line) + m_line->setPosition(QPointF(m_line->x(), y)); +} + +void QSGText::doLayout() +{ + Q_D(QSGText); + d->updateSize(); +} + +/*! + \qmlsignal QtQuick2::Text::onLineLaidOut(line) + + This handler is called for every line during the layout process. + This gives the opportunity to position and resize a line as it is being laid out. + It can for example be used to create columns or lay out text around objects. + + The properties of a line are: + \list + \o number (read-only) + \o x + \o y + \o width + \o height + \endlist + + For example, this will move the first 5 lines of a text element by 100 pixels to the right: + \code + onLineLaidOut: { + if (line.number < 5) { + line.x = line.x + 100 + line.width = line.width - 100 + } + } + \endcode +*/ + +bool QSGTextPrivate::isLineLaidOutConnected() +{ + static int idx = this->signalIndex("lineLaidOut(QSGTextLine*)"); + return this->isSignalConnected(idx); +} + +void QSGTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, qreal elideWidth = 0) +{ + Q_Q(QSGText); + +#if defined(Q_OS_MAC) + if (QThread::currentThread() != paintingThread) { +#endif + if (!line.lineNumber()) + linesRects.clear(); + + if (!textLine) + textLine = new QSGTextLine; + textLine->setLine(&line); + textLine->setY(height); + textLine->setHeight(0); + + // use the text item's width by default if it has one and wrap is on + if (q->widthValid() && q->wrapMode() != QSGText::NoWrap) + textLine->setWidth(q->width() - elideWidth); + else + textLine->setWidth(INT_MAX); + if (lineHeight != 1.0) + textLine->setHeight((lineHeightMode == QSGText::FixedHeight) ? lineHeight : line.height() * lineHeight); + + emit q->lineLaidOut(textLine); + + linesRects << QRectF(textLine->x(), textLine->y(), textLine->width(), textLine->height()); + height += textLine->height(); + +#if defined(Q_OS_MAC) + } else { + if (line.lineNumber() < linesRects.count()) { + QRectF r = linesRects.at(line.lineNumber()); + line.setLineWidth(r.width()); + line.setPosition(r.topLeft()); + } + } +#endif +} + /*! Lays out the QSGTextPrivate::layout QTextLayout in the constraints of the QSGText. @@ -420,6 +575,9 @@ QRect QSGTextPrivate::setupTextLayout() layout.setText(elidedText); } + qreal height = 0; + bool customLayout = isLineLaidOutConnected(); + if (maximumLineCountValid) { layout.beginLayout(); if (!lineWidth) @@ -432,17 +590,23 @@ QRect QSGTextPrivate::setupTextLayout() break; visibleCount++; - if (lineWidth) + + if (customLayout) + setupCustomLineGeometry(line, height); + else if (lineWidth) line.setLineWidth(lineWidth); visibleTextLength += line.textLength(); if (--linesLeft == 0) { if (visibleTextLength < text.length()) { truncate = true; - if (elideMode==QSGText::ElideRight && q->widthValid()) { + if (elideMode == QSGText::ElideRight && q->widthValid()) { qreal elideWidth = fm.width(elideChar); // Need to correct for alignment - line.setLineWidth(lineWidth-elideWidth); + if (customLayout) + setupCustomLineGeometry(line, height, elideWidth); + else + line.setLineWidth(lineWidth - elideWidth); if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) { line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y())); elidePos.setX(line.naturalTextRect().left() - elideWidth); @@ -468,18 +632,23 @@ QRect QSGTextPrivate::setupTextLayout() if (!line.isValid()) break; visibleCount++; - if (lineWidth) - line.setLineWidth(lineWidth); + if (customLayout) + setupCustomLineGeometry(line, height); + else { + if (lineWidth) + line.setLineWidth(lineWidth); + } } layout.endLayout(); } - qreal height = 0; + height = 0; QRectF br; for (int i = 0; i < layout.lineCount(); ++i) { QTextLine line = layout.lineAt(i); // set line spacing - line.setPosition(QPointF(line.position().x(), height)); + if (!customLayout) + line.setPosition(QPointF(line.position().x(), height)); if (elideText && i == layout.lineCount()-1) { elidePos.setY(height + fm.ascent()); br = br.united(QRectF(elidePos, QSizeF(fm.width(elideChar), fm.ascent()))); @@ -487,7 +656,8 @@ QRect QSGTextPrivate::setupTextLayout() br = br.united(line.naturalTextRect()); height += (lineHeightMode == QSGText::FixedHeight) ? lineHeight : line.height() * lineHeight; } - br.setHeight(height); + if (!customLayout) + br.setHeight(height); if (!q->widthValid()) naturalWidth = br.width(); @@ -965,6 +1135,7 @@ void QSGText::setText(const QString &n) } d->determineHorizontalAlignment(); } + d->textHasChanged = true; d->updateLayout(); emit textChanged(d->text); } @@ -1500,7 +1671,8 @@ QSGNode *QSGText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) // We need to make sure the layout is done in the current thread #if defined(Q_OS_MAC) - if (d->layoutThread != QThread::currentThread()) + d->paintingThread = QThread::currentThread(); + if (d->layoutThread != d->paintingThread) d->updateLayout(); #endif @@ -1555,7 +1727,6 @@ QSGNode *QSGText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) node->setMatrix(QMatrix4x4()); if (d->richText) { - d->ensureDoc(); node->addTextDocument(bounds.topLeft(), d->doc, QColor(), d->style, d->styleColor); diff --git a/src/declarative/items/qsgtext_p.h b/src/declarative/items/qsgtext_p.h index 725eeb2..aa07c8a 100644 --- a/src/declarative/items/qsgtext_p.h +++ b/src/declarative/items/qsgtext_p.h @@ -55,6 +55,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QSGTextPrivate; +class QSGTextLine; class Q_DECLARATIVE_PRIVATE_EXPORT QSGText : public QSGImplicitSizeItem { Q_OBJECT @@ -172,6 +173,7 @@ public: qreal paintedHeight() const; QRectF boundingRect() const; + Q_INVOKABLE void doLayout(); Q_SIGNALS: void textChanged(const QString &text); @@ -192,6 +194,7 @@ Q_SIGNALS: void lineHeightChanged(qreal lineHeight); void lineHeightModeChanged(LineHeightMode mode); void effectiveHorizontalAlignmentChanged(); + void lineLaidOut(QSGTextLine *line); protected: void mousePressEvent(QMouseEvent *event); @@ -206,9 +209,43 @@ private: Q_DECLARE_PRIVATE(QSGText) }; +class QTextLine; +class Q_AUTOTEST_EXPORT QSGTextLine : public QObject +{ + Q_OBJECT + Q_PROPERTY(int number READ number) + Q_PROPERTY(qreal width READ width WRITE setWidth) + Q_PROPERTY(qreal height READ height WRITE setHeight) + Q_PROPERTY(qreal x READ x WRITE setX) + Q_PROPERTY(qreal y READ y WRITE setY) + +public: + QSGTextLine(); + + void setLine(QTextLine* line); + int number() const; + + qreal width() const; + void setWidth(qreal width); + + qreal height() const; + void setHeight(qreal height); + + qreal x() const; + void setX(qreal x); + + qreal y() const; + void setY(qreal y); + +private: + QTextLine *m_line; + qreal m_height; +}; + QT_END_NAMESPACE QML_DECLARE_TYPE(QSGText) +QML_DECLARE_TYPE(QSGTextLine) QT_END_HEADER diff --git a/src/declarative/items/qsgtext_p_p.h b/src/declarative/items/qsgtext_p_p.h index ddd54b6..8b83263 100644 --- a/src/declarative/items/qsgtext_p_p.h +++ b/src/declarative/items/qsgtext_p_p.h @@ -80,6 +80,7 @@ public: bool setHAlign(QSGText::HAlignment, bool forceAlign = false); void mirrorChange(); QTextDocument *textDocument(); + bool isLineLaidOutConnected(); QString text; QFont font; @@ -121,6 +122,7 @@ public: bool layoutTextElided:1; bool richTextAsImage:1; bool textureImageCacheDirty:1; + bool textHasChanged:1; QRect layedOutTextRect; QSize paintedSize; @@ -132,11 +134,14 @@ public: QSGTextDocumentWithImageResources *doc; QRect setupTextLayout(); + void setupCustomLineGeometry(QTextLine &line, qreal &height, qreal elideWidth); QPixmap textLayoutImage(bool drawStyle); void drawTextLayout(QPainter *p, const QPointF &pos, bool drawStyle); bool isLinkActivatedConnected(); QString anchorAt(const QPointF &pos); QTextLayout layout; + QList linesRects; + QSGTextLine *textLine; static QPixmap drawOutline(const QPixmap &source, const QPixmap &styleSource); static QPixmap drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset); @@ -154,6 +159,7 @@ public: #if defined(Q_OS_MAC) QThread *layoutThread; + QThread *paintingThread; #endif }; diff --git a/tests/auto/declarative/qsgtext/data/lineLayout.qml b/tests/auto/declarative/qsgtext/data/lineLayout.qml new file mode 100644 index 0000000..cb24747 --- /dev/null +++ b/tests/auto/declarative/qsgtext/data/lineLayout.qml @@ -0,0 +1,35 @@ +import QtQuick 2.0 + +Rectangle { + id: main + width: 800; height: 600 + + property real off: 0 + + Text { + id: myText + objectName: "myText" + wrapMode: Text.WordWrap + font.pixelSize: 14 + textFormat: Text.StyledText + focus: true + + text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at ante dui. Sed eu egestas est. +

Maecenas nec libero leo. Sed ac leo eget ipsum ultricies viverra sit amet eu orci. Praesent et tortor risus, viverra accumsan sapien. Sed faucibus eleifend lectus, sed euismod urna porta eu. Aenean ultricies lectus ut orci dictum quis convallis nisi ultrices. Nunc elit mi, iaculis a porttitor rutrum, venenatis malesuada nisi. Suspendisse turpis quam, euismod non imperdiet et, rutrum nec ligula. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam semper tristique metus eu sodales. Integer eget risus ipsum. Quisque ut risus ut nulla tristique volutpat at sit amet nisl. Aliquam pulvinar auctor diam nec bibendum.

Quisque luctus sapien id arcu volutpat pharetra. Praesent pretium imperdiet euismod. Integer fringilla rhoncus condimentum. Quisque sit amet ornare nulla. Cras sapien augue, sagittis a dictum id, suscipit et nunc. Cras vitae augue in enim elementum venenatis sed nec risus. Sed nisi quam, mollis quis auctor ac, vestibulum in neque. Vivamus eu justo risus. Suspendisse vel mollis est. Vestibulum gravida interdum mi, in molestie neque gravida in. Donec nibh odio, mattis facilisis vulputate et, scelerisque ut felis. Sed ornare eros nec odio aliquam eu varius augue adipiscing. Vivamus sit amet massa dapibus sapien pulvinar consectetur a sit amet felis. Cras non mi id libero dictum iaculis id dignissim eros. Praesent eget enim dui, sed bibendum neque. Ut interdum nisl id leo malesuada ornare. Pellentesque id nisl eu odio volutpat posuere et at massa. Pellentesque nec lorem justo. Integer sem urna, pharetra sed sagittis vitae, condimentum ac felis. Ut vitae sapien ac tortor adipiscing pharetra. Cras tristique urna tempus ante volutpat eleifend non eu ligula. Mauris sodales nisl et lorem tristique sodales. Mauris arcu orci, vehicula semper cursus ac, dapibus ut mi." + + onLineLaidOut: { + line.width = line.number * 15 + if (line.number === 30 || line.number === 60) { + main.off = line.y + } + if (line.number >= 30) { + line.x = line.width + 30 + line.y -= main.off + } + if (line.number >= 60) { + line.x = line.width * 2 + 60 + line.height = 20 + } + } + } +} diff --git a/tests/auto/declarative/qsgtext/tst_qsgtext.cpp b/tests/auto/declarative/qsgtext/tst_qsgtext.cpp index dd11789..1428f32 100644 --- a/tests/auto/declarative/qsgtext/tst_qsgtext.cpp +++ b/tests/auto/declarative/qsgtext/tst_qsgtext.cpp @@ -103,10 +103,11 @@ private slots: void clickLink(); - void implicitSize_data(); void implicitSize(); + void lineLaidOut(); + private: QStringList standard; @@ -1402,6 +1403,32 @@ void tst_qsgtext::implicitSize() delete textObject; } +void tst_qsgtext::lineLaidOut() +{ + QSGView *canvas = createView(SRCDIR "/data/lineLayout.qml"); + + QSGText *myText = canvas->rootObject()->findChild("myText"); + QVERIFY(myText != 0); + + QSGTextPrivate *textPrivate = QSGTextPrivate::get(myText); + QVERIFY(textPrivate != 0); + + QTextDocument *doc = textPrivate->textDocument(); + QVERIFY(doc == 0); + + QVERIFY(myText->lineCount() == textPrivate->linesRects.count()); + + for (int i = 0; i < textPrivate->linesRects.count(); ++i) { + QRectF r = textPrivate->linesRects.at(i); + QVERIFY(r.width() == i * 15); + if (i >= 30) + QVERIFY(r.x() == r.width() + 30); + if (i >= 60) { + QVERIFY(r.x() == r.width() * 2 + 60); + QVERIFY(r.height() == 20); + } + } +} QTEST_MAIN(tst_qsgtext) diff --git a/tests/testapplications/textlayout/styledtext-layout.qml b/tests/testapplications/textlayout/styledtext-layout.qml new file mode 100644 index 0000000..9ef30ef --- /dev/null +++ b/tests/testapplications/textlayout/styledtext-layout.qml @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: main + width: 1024; height: 1024 + focus: true + + property real offset: 0 + property real margin: 15 + + Keys.onLeftPressed: myText.horizontalAlignment = Text.AlignLeft + Keys.onUpPressed: myText.horizontalAlignment = Text.AlignHCenter + Keys.onRightPressed: myText.horizontalAlignment = Text.AlignRight + Keys.onDownPressed: myText.horizontalAlignment = Text.AlignJustify + + Text { + id: myText + anchors.fill: parent + anchors.margins: 20 + wrapMode: Text.WordWrap + font.family: "Times New Roman" + font.pixelSize: 18 + textFormat: Text.StyledText + horizontalAlignment: Text.AlignJustify + + text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at ante dui sed eu egestas est facilis www.nokia.com.
Curabitur ante est, pulvinar quis adipiscing a, iaculis id ipsum. Phasellus id neque id velit facilisis cursus ac sit amet nibh. Donec enim arcu, pharetra non semper nec, iaculis eget elit. Nunc blandit condimentum odio vel egestas.

  • Coffee
    1. Espresso
    2. Cappuccino
    3. Flat White
    4. Latte
  • Juice
    1. Orange
    2. Apple
    3. Pineapple
    4. Tomato

Proin consectetur sapien in ipsum lacinia sit amet mattis orci interdum. Quisque vitae accumsan lectus. Ut nisi turpis, sollicitudin ut dignissim id, fermentum ac est. Maecenas nec libero leo. Sed ac leo eget ipsum ultricies viverra sit amet eu orci. Praesent et tortor risus, viverra accumsan sapien. Sed faucibus eleifend lectus, sed euismod urna porta eu. Aenean ultricies lectus ut orci dictum quis convallis nisi ultrices. Nunc elit mi, iaculis a porttitor rutrum, venenatis malesuada nisi. Suspendisse turpis quam, euismod non imperdiet et, rutrum nec ligula. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam semper tristique metus eu sodales. Integer eget risus ipsum. Quisque ut risus ut nulla tristique volutpat at sit amet nisl. Aliquam pulvinar auctor diam nec bibendum. Quisque luctus sapien id arcu volutpat pharetra. Praesent pretium imperdiet euismod. Integer fringilla rhoncus condimentum. Quisque sit amet ornare nulla. Cras sapien augue, sagittis a dictum id, suscipit et nunc. Cras vitae augue in enim elementum venenatis sed nec risus. Sed nisi quam, mollis quis auctor ac, vestibulum in neque. Vivamus eu justo risus. Suspendisse vel mollis est. Vestibulum gravida interdum mi, in molestie neque gravida in.

Donec nibh odio, mattis facilisis vulputate et, scelerisque ut felis. Sed ornare eros nec odio aliquam eu varius augue adipiscing. Vivamus sit amet massa dapibus sapien pulvinar consectetur a sit amet felis. Cras non mi id libero dictum iaculis id dignissim eros. Praesent eget enim dui, sed bibendum neque. Ut interdum nisl id leo malesuada ornare.

Pellentesque id nisl eu odio volutpat posuere et at massa. Pellentesque nec lorem justo. Integer sem urna, pharetra sed sagittis vitae, condimentum ac felis. Ut vitae sapien ac tortor adipiscing pharetra. Cras tristique urna tempus ante volutpat eleifend non eu ligula. Mauris sodales nisl et lorem tristique sodales. Mauris arcu orci, vehicula semper cursus ac, dapibus ut mi. Cras orci ligula, lacinia non laoreet non, feugiat eget lorem. Duis commodo urna nunc. Ut eu diam quis magna volutpat auctor. Duis non nibh non leo aliquet gravida. Aenean diam velit, eleifend sed porta eu, malesuada sed erat. In hac habitasse platea dictumst. Ut nulla ligula, tincidunt ac volutpat nec, accumsan at risus. Donec eget ipsum sit amet nulla tempus auctor ut non massa. Donec enim purus, consectetur viverra congue vitae, vehicula eu sapien. Ut aliquam iaculis metus, a bibendum nisi fringilla ut. Maecenas ut libero augue, vitae tristique diam. Vivamus nec rhoncus ipsum. Maecenas rutrum, libero sit amet ultrices cursus, elit massa laoreet odio, in luctus elit quam eu quam. Sed non diam urna. Maecenas fringilla feugiat malesuada. In tellus nibh, gravida vitae cursus mollis, tincidunt eu urna. Cras turpis lorem, dictum in feugiat id, gravida eu nulla. In ultricies nisl in sapien consectetur eu ultricies nisl facilisis. Nam id mauris a leo pretium facilisis eget quis est. Fusce fermentum quam in metus facilisis semper." + + + onLineLaidOut: { + line.width = width / 2 - (2 * margin) + if (line.number === 40) { + main.offset = line.y + } + if (line.number >= 40) { + line.x = width / 2 + margin + line.y -= main.offset + } + if ((line.y + line.height) > rect.y && line.y < (rect.y + rect.height)) { + if (line.number < 40) + line.width = Math.min((rect.x - line.x), line.width) + else { + line.x = Math.max((rect.x + rect.width), width / 2 + margin) + line.width = Math.min((width - margin - line.x), line.width) + } + } + } + + Item { + id: rect + x: 280; y: 200 + width: 300; height: 300 + + Rectangle { + anchors { fill: parent; leftMargin: 15; rightMargin: 15 } + color: "lightsteelblue"; opacity: 0.3 + } + + MouseArea { + anchors.fill: parent + drag.target: rect + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: mouse.button == Qt.RightButton ? myText.font.pixelSize -= 1 : myText.font.pixelSize += 1 + onPositionChanged: myText.doLayout() + } + } + } + +} -- 2.7.4