From efd0fed4dec904b6d0257dffe5ea3e2939650f44 Mon Sep 17 00:00:00 2001 From: J-P Nurmi <jpnurmi@digia.com> Date: Tue, 14 May 2013 10:39:43 +0200 Subject: [PATCH] TextArea: fix word wrap layout Since scrollbars affect the document/viewport size and vice versa, we must allow the layout loop to recurse twice until the sizes stabilize. Furthermore, avoid nasty content size binding loops (from ScrollView) by providing a specialized Flickable item that TextArea has full control over. Task-number: QTBUG-30832 Change-Id: I74fe6c5017e75aa411fdbb64087afa18e1221ce9 Reviewed-by: Jens Bache-Wiig <jens.bache-wiig@digia.com> --- src/controls/TextArea.qml | 161 +++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 73 deletions(-) diff --git a/src/controls/TextArea.qml b/src/controls/TextArea.qml index a818779a3..6dab90fd3 100644 --- a/src/controls/TextArea.qml +++ b/src/controls/TextArea.qml @@ -609,12 +609,11 @@ ScrollView { property alias backgroundColor: colorRect.color /*! \internal */ - property int documentMargins: 4 + property int __documentMargin: 4 width: 280 height: 120 - flickableItem.contentWidth: edit.paintedWidth + (2 * documentMargins) frameVisible: true activeFocusOnTab: true @@ -629,84 +628,100 @@ ScrollView { */ property alias textDocument: edit.textDocument - TextEdit { - id: edit - focus: true + Flickable { + id: flickable - SystemPalette { - id: palette - colorGroup: enabled ? SystemPalette.Active : SystemPalette.Disabled - } + interactive: false + anchors.fill: parent - Rectangle { - id: colorRect - parent: viewport - anchors.fill: parent - color: palette.base - z: -1 - } + TextEdit { + id: edit + focus: true + + SystemPalette { + id: palette + colorGroup: enabled ? SystemPalette.Active : SystemPalette.Disabled + } + + Rectangle { + id: colorRect + parent: viewport + anchors.fill: parent + color: palette.base + z: -1 + } + + property int layoutRecursionDepth: 0 + + function doLayout() { + // scrollbars affect the document/viewport size and vice versa, so we + // must allow the layout loop to recurse twice until the sizes stabilize + if (layoutRecursionDepth <= 2) { + layoutRecursionDepth++ + + var margins = 2 * __documentMargin - property bool recursionGuard: false - - function doLayout() { - if (!recursionGuard) { - recursionGuard = true - if (wrapMode == TextEdit.NoWrap) { - __horizontalScrollBar.visible = edit.paintedWidth + (2 * documentMargins) > area.viewport.width - edit.width = edit.paintedWidth + (2 * documentMargins) - } else { - __horizontalScrollBar.visible = false - edit.width = area.viewport.width - (2 * documentMargins) + if (wrapMode == TextEdit.NoWrap) { + __horizontalScrollBar.visible = edit.contentWidth > viewport.width - margins + edit.width = Math.max(viewport.width - margins, edit.contentWidth) + } else { + __horizontalScrollBar.visible = false + edit.width = viewport.width - margins + } + edit.height = Math.max(viewport.height - margins, edit.contentHeight) + + flickable.contentWidth = edit.contentWidth + margins + flickable.contentHeight = edit.contentHeight + margins + + layoutRecursionDepth-- } - edit.height = Math.max(area.viewport.height - (2 * documentMargins), paintedHeight + (2 * documentMargins)) - recursionGuard = false } - } - Connections { - target: area.viewport - onWidthChanged: edit.doLayout() - onHeightChanged: edit.doLayout() - } - onPaintedWidthChanged: edit.doLayout() - onPaintedHeightChanged: edit.doLayout() - onWrapModeChanged: edit.doLayout() - - renderType: Text.NativeRendering - - color: palette.text - selectionColor: palette.highlight - selectedTextColor: palette.highlightedText - wrapMode: TextEdit.WordWrap - x: documentMargins - y: documentMargins - - selectByMouse: true - readOnly: false - - KeyNavigation.priority: KeyNavigation.BeforeItem - KeyNavigation.tab: area.tabChangesFocus ? area.KeyNavigation.tab : null - KeyNavigation.backtab: area.tabChangesFocus ? area.KeyNavigation.backtab : null - - // keep textcursor within scroll view - onCursorPositionChanged: { - if (cursorRectangle.y >= flickableItem.contentY + viewport.height - 1.5*cursorRectangle.height - documentMargins) - flickableItem.contentY = cursorRectangle.y - viewport.height + 1.5*cursorRectangle.height + documentMargins - else if (cursorRectangle.y < flickableItem.contentY) - flickableItem.contentY = cursorRectangle.y - - if (cursorRectangle.x >= flickableItem.contentX + viewport.width - documentMargins) { - flickableItem.contentX = cursorRectangle.x - viewport.width + documentMargins - } else if (cursorRectangle.x < flickableItem.contentX) - flickableItem.contentX = cursorRectangle.x - } - onLinkActivated: area.linkActivated(link) + Connections { + target: area.viewport + onWidthChanged: edit.doLayout() + onHeightChanged: edit.doLayout() + } + onContentWidthChanged: edit.doLayout() + onContentHeightChanged: edit.doLayout() + onWrapModeChanged: edit.doLayout() + + renderType: Text.NativeRendering + + color: palette.text + selectionColor: palette.highlight + selectedTextColor: palette.highlightedText + wrapMode: TextEdit.WordWrap + x: __documentMargin + y: __documentMargin + + selectByMouse: true + readOnly: false + + KeyNavigation.priority: KeyNavigation.BeforeItem + KeyNavigation.tab: area.tabChangesFocus ? area.KeyNavigation.tab : null + KeyNavigation.backtab: area.tabChangesFocus ? area.KeyNavigation.backtab : null + + // keep textcursor within scroll view + onCursorPositionChanged: { + if (cursorRectangle.y >= flickableItem.contentY + viewport.height - 1.5*cursorRectangle.height - __documentMargin) + flickableItem.contentY = cursorRectangle.y - viewport.height + 1.5*cursorRectangle.height + __documentMargin + else if (cursorRectangle.y < flickableItem.contentY) + flickableItem.contentY = cursorRectangle.y + + if (cursorRectangle.x >= flickableItem.contentX + viewport.width - __documentMargin) { + flickableItem.contentX = cursorRectangle.x - viewport.width + __documentMargin + } else if (cursorRectangle.x < flickableItem.contentX) + flickableItem.contentX = cursorRectangle.x + } + onLinkActivated: area.linkActivated(link) - MouseArea { - parent: area.viewport - anchors.fill: parent - cursorShape: Qt.IBeamCursor - acceptedButtons: Qt.NoButton + MouseArea { + parent: area.viewport + anchors.fill: parent + cursorShape: Qt.IBeamCursor + acceptedButtons: Qt.NoButton + } } } -- GitLab