Commit 6fcaca37 authored by Yann Bodson's avatar Yann Bodson Committed by Qt by Nokia

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/5351Reviewed-by: default avatarYann Bodson <yann.bodson@nokia.com>
Sanity-Review: Yann Bodson <yann.bodson@nokia.com>
parent 6a9d97f0
......@@ -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
......
......@@ -159,6 +159,7 @@ static void qt_sgitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QDeclarativePathElement>();
qmlRegisterType<QDeclarativeCurve>();
qmlRegisterType<QSGScaleGrid>();
qmlRegisterType<QSGTextLine>();
#ifndef QT_NO_VALIDATOR
qmlRegisterType<QValidator>();
#endif
......
......@@ -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<QUrl> 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);
......
......@@ -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
......
......@@ -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<QRectF> 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
};
......
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: "<b>Lorem ipsum</b> dolor sit amet, consectetur adipiscing elit. Integer at ante dui. Sed eu egestas est.
<br/><p><i>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.</i><br/><p>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
}
}
}
}
......@@ -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<QSGText*>("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)
......
/****************************************************************************
**
** 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 <a href=\"www.nokia.com\">www.nokia.com</a>.<br/>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.<br><ul type=\"bullet\"><li>Coffee<ol type=\"a\"><li>Espresso<li><b>Cappuccino</b><li><i>Flat White</i><li>Latte</ol><li>Juice<ol type=\"1\"><li>Orange</li><li>Apple</li><li>Pineapple</li><li>Tomato</li></ol></li></ul><p><font color=\"#434343\"><i>Proin consectetur <b>sapien</b> 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.</i></font><br><br> 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.<br><br>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. <font color=\"green\">Aenean diam velit, eleifend sed porta eu, malesuada sed erat.</font> 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()
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment