diff options
author | Konstantin Ritt <ritt.ks@gmail.com> | 2019-09-11 21:54:53 +0300 |
---|---|---|
committer | Konstantin Ritt <ritt.ks@gmail.com> | 2019-09-19 11:36:26 +0000 |
commit | 6815f353e5a73c0dcf39fbfc91c6a2c1b0784324 (patch) | |
tree | 27681102f10ef27f0cb96ca4e39f026d1a0e6f87 | |
parent | a89c3bc67ea6c76bfc89d64f235ebf5cb4b0fca4 (diff) |
TextArea: prevent changing size of background recursively
When the x/y position of background depends on the height/width of
background and these values are not constant, the if statement in
the method resizeBackground() will always pass. And since
`resizingBackground` guard wasn't checked, any geometry change
will always call resizeBackground() and then call
themself recursively (via the change listener),
that means the height/width of background will
always be reset, no matter what value you set.
Another part of the issue was in determining the extra bits too late:
in case the background gets parented by the flickable, the new child
caused the flickable to re-calculate its metrics and thus resize
the background *prior* to remembering if it has w/h set.
As a side effect, this fix also brings the possibility to reset
previously set w/h to get the default background sizing behavior.
Inspired by da06da57002b64cf4bcde0ca708b3275a5f919ae
[ChangeLog][QtQuick][QQuickTextArea] prevent changing size
of background recursively in construction
Fixes: QTBUG-76369
Change-Id: Ide51ec1ebab63605ae3bfcc10a76a28be960ef36
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r-- | src/quicktemplates2/qquicktextarea.cpp | 21 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_textarea.qml | 68 |
2 files changed, 82 insertions, 7 deletions
diff --git a/src/quicktemplates2/qquicktextarea.cpp b/src/quicktemplates2/qquicktextarea.cpp index 7fdc8f0a..f7b8969c 100644 --- a/src/quicktemplates2/qquicktextarea.cpp +++ b/src/quicktemplates2/qquicktextarea.cpp @@ -435,9 +435,16 @@ void QQuickTextAreaPrivate::resizeFlickableContent() void QQuickTextAreaPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) { - Q_UNUSED(item); - Q_UNUSED(change); Q_UNUSED(diff); + if (!resizingBackground && item == background) { + QQuickItemPrivate *p = QQuickItemPrivate::get(item); + // Only set hasBackgroundWidth/Height if it was a width/height change, + // otherwise we're prevented from setting a width/height in the future. + if (change.widthChange()) + extra.value().hasBackgroundWidth = p->widthValid; + if (change.heightChange()) + extra.value().hasBackgroundHeight = p->heightValid; + } if (flickable) resizeFlickableControl(); @@ -627,17 +634,17 @@ void QQuickTextArea::setBackground(QQuickItem *background) d->background = background; if (background) { + QQuickItemPrivate *p = QQuickItemPrivate::get(background); + if (p->widthValid || p->heightValid) { + d->extra.value().hasBackgroundWidth = p->widthValid; + d->extra.value().hasBackgroundHeight = p->heightValid; + } if (d->flickable) background->setParentItem(d->flickable); else background->setParentItem(this); if (qFuzzyIsNull(background->z())) background->setZ(-1); - QQuickItemPrivate *p = QQuickItemPrivate::get(background); - if (p->widthValid || p->heightValid) { - d->extra.value().hasBackgroundWidth = p->widthValid; - d->extra.value().hasBackgroundHeight = p->heightValid; - } if (isComponentComplete()) d->resizeBackground(); QQuickControlPrivate::addImplicitSizeListener(background, d, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry); diff --git a/tests/auto/controls/data/tst_textarea.qml b/tests/auto/controls/data/tst_textarea.qml index ee40c9b7..1e455ffc 100644 --- a/tests/auto/controls/data/tst_textarea.qml +++ b/tests/auto/controls/data/tst_textarea.qml @@ -688,4 +688,72 @@ TestCase { compare(control.background.width, 100) compare(control.background.height, 100) } + + // QTBUG-76369 + Component { + id: testResizeBackground + Item { + width: 200 + height: 200 + property alias textArea: textArea + ScrollView { + anchors.fill: parent + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + TextArea { + id: textArea + // workaround test failing due to default insets on Imagine + topInset: undefined + leftInset: undefined + rightInset: undefined + bottomInset: undefined + wrapMode : TextEdit.WordWrap + readOnly: false + selectByMouse: true + focus: true + text: "test message" + + background: Rectangle { + y: parent.height - height - textArea.bottomPadding / 2 + implicitWidth: 120 + height: textArea.activeFocus ? 2 : 1 + } + } + } + } + } + + function test_resize_background() { + var control = createTemporaryObject(testResizeBackground, testCase) + + compare(control.textArea.background.width, control.width) + compare(control.textArea.background.height, 1) + control.width = 400 + control.height = 400 + compare(control.textArea.background.width, control.width) + compare(control.textArea.background.height, 1) + control.width = 200 + control.height = 200 + compare(control.textArea.background.width, control.width) + compare(control.textArea.background.height, 1) + + // hasBackgroundWidth=true + control.textArea.background.width = 1 + compare(control.textArea.background.width, 1) + compare(control.textArea.background.height, 1) + control.width = 400 + control.height = 400 + compare(control.textArea.background.width, 1) + compare(control.textArea.background.height, 1) + // hasBackgroundHeight=false + control.textArea.background.height = undefined + compare(control.textArea.background.width, 1) + compare(control.textArea.background.height, 0) + control.textArea.background.y = 0 + compare(control.textArea.background.width, 1) + compare(control.textArea.background.height, control.height) + control.width = 200 + control.height = 200 + compare(control.textArea.background.width, 1) + compare(control.textArea.background.height, control.height) + } } |