diff options
| -rw-r--r-- | src/controls/Private/TextHandle.qml | 91 | ||||
| -rw-r--r-- | src/controls/Private/private.pri | 1 | ||||
| -rw-r--r-- | src/controls/Private/qmldir | 1 | ||||
| -rw-r--r-- | src/controls/Styles/Base/TextAreaStyle.qml | 34 | ||||
| -rw-r--r-- | src/controls/Styles/Base/TextFieldStyle.qml | 34 | ||||
| -rw-r--r-- | src/controls/TextArea.qml | 133 | ||||
| -rw-r--r-- | src/controls/TextField.qml | 122 | ||||
| -rw-r--r-- | tests/manual/texthandles/main.cpp | 49 | ||||
| -rw-r--r-- | tests/manual/texthandles/main.qml | 169 | ||||
| -rw-r--r-- | tests/manual/texthandles/texthandles.pro | 11 | ||||
| -rw-r--r-- | tests/manual/texthandles/texthandles.qmlproject | 16 | ||||
| -rw-r--r-- | tests/manual/texthandles/texthandles.qrc | 5 |
12 files changed, 644 insertions, 22 deletions
diff --git a/src/controls/Private/TextHandle.qml b/src/controls/Private/TextHandle.qml new file mode 100644 index 000000000..34daa4ab0 --- /dev/null +++ b/src/controls/Private/TextHandle.qml @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +import QtQuick 2.2 + +Loader { + id: handle + + property Item editor + property int minimum: -1 + property int maximum: -1 + property int position: -1 + property alias delegate: handle.sourceComponent + + readonly property alias pressed: mouse.pressed + + readonly property real handleX: x + (item ? item.x : 0) + readonly property real handleY: y + (item ? item.y : 0) + readonly property real handleWidth: item ? item.width : 0 + readonly property real handleHeight: item ? item.height : 0 + + property Item control + property QtObject styleData: QtObject { + readonly property alias pressed: mouse.pressed + readonly property alias position: handle.position + readonly property real lineHeight: position !== -1 ? editor.positionToRectangle(position).height + : editor.cursorRectangle.height + } + + MouseArea { + id: mouse + anchors.fill: item + property point offset + onPressed: offset = Qt.point(x + mouse.x, y + mouse.y) + onPositionChanged: { + var pt = mapToItem(editor, mouse.x - offset.x, mouse.y - offset.y) + + // limit vertically within mix/max coordinates or content bounds + var min = (minimum !== -1) ? minimum : 0 + var max = (maximum !== -1) ? maximum : editor.length - 1 + pt.y = Math.max(pt.y, editor.positionToRectangle(min).y) + pt.y = Math.min(pt.y, editor.positionToRectangle(max).y) + + var pos = editor.positionAt(pt.x, pt.y) + + // limit horizontally within min/max character positions + if (minimum !== -1) + pos = Math.max(pos, minimum) + if (maximum !== -1) + pos = Math.min(pos, maximum) + + handle.position = pos + } + } +} diff --git a/src/controls/Private/private.pri b/src/controls/Private/private.pri index f94468540..f2da1ec97 100644 --- a/src/controls/Private/private.pri +++ b/src/controls/Private/private.pri @@ -47,6 +47,7 @@ PRIVATE_QML_FILES += \ $$PWD/ScrollViewHelper.qml \ $$PWD/ScrollBar.qml \ $$PWD/TableViewSelection.qml \ + $$PWD/TextHandle.qml \ $$PWD/TextSingleton.qml \ $$PWD/FocusFrame.qml \ $$PWD/ColumnMenuContent.qml \ diff --git a/src/controls/Private/qmldir b/src/controls/Private/qmldir index d31483e31..589087bf4 100644 --- a/src/controls/Private/qmldir +++ b/src/controls/Private/qmldir @@ -25,3 +25,4 @@ ColumnMenuContent 1.0 ColumnMenuContent.qml ContentItem 1.0 ContentItem.qml HoverButton 1.0 HoverButton.qml singleton TextSingleton 1.0 TextSingleton.qml +TextHandle 1.0 TextHandle.qml diff --git a/src/controls/Styles/Base/TextAreaStyle.qml b/src/controls/Styles/Base/TextAreaStyle.qml index 7ad5686f9..4ffefe639 100644 --- a/src/controls/Styles/Base/TextAreaStyle.qml +++ b/src/controls/Styles/Base/TextAreaStyle.qml @@ -96,4 +96,38 @@ ScrollViewStyle { \sa Text::renderType */ property int renderType: Text.NativeRendering + + /*! The cursor handle. + \since QtQuick.Controls.Styles 1.3 + + The parent of the handle is positioned to the top left corner of + the cursor position. The interactive area is determined by the + geometry of the handle delegate. + + The following read-only properties are available within the scope + of the handle delegate: + \table + \row \li \b {styleData.pressed} : bool \li Whether the handle is pressed. + \row \li \b {styleData.position} : int \li The character position of the handle. + \row \li \b {styleData.lineHeight} : real \li The height of the line the handle is on. + \endtable + */ + property Component cursorHandle + + /*! The selection handle. + \since QtQuick.Controls.Styles 1.3 + + The parent of the handle is positioned to the top left corner of + the first selected character. The interactive area is determined + by the geometry of the handle delegate. + + The following read-only properties are available within the scope + of the handle delegate: + \table + \row \li \b {styleData.pressed} : bool \li Whether the handle is pressed. + \row \li \b {styleData.position} : int \li The character position of the handle. + \row \li \b {styleData.lineHeight} : real \li The height of the line the handle is on. + \endtable + */ + property Component selectionHandle } diff --git a/src/controls/Styles/Base/TextFieldStyle.qml b/src/controls/Styles/Base/TextFieldStyle.qml index d999551c0..dc25033aa 100644 --- a/src/controls/Styles/Base/TextFieldStyle.qml +++ b/src/controls/Styles/Base/TextFieldStyle.qml @@ -159,4 +159,38 @@ Style { anchors.fill: parent } } + + /*! The cursor handle. + \since QtQuick.Controls.Styles 1.3 + + The parent of the handle is positioned to the top left corner of + the cursor position. The interactive area is determined by the + geometry of the handle delegate. + + The following read-only properties are available within the scope + of the handle delegate: + \table + \row \li \b {styleData.pressed} : bool \li Whether the handle is pressed. + \row \li \b {styleData.position} : int \li The character position of the handle. + \row \li \b {styleData.lineHeight} : real \li The height of the line the handle is on. + \endtable + */ + property Component cursorHandle + + /*! The selection handle. + \since QtQuick.Controls.Styles 1.3 + + The parent of the handle is positioned to the top left corner of + the first selected character. The interactive area is determined + by the geometry of the handle delegate. + + The following read-only properties are available within the scope + of the handle delegate: + \table + \row \li \b {styleData.pressed} : bool \li Whether the handle is pressed. + \row \li \b {styleData.position} : int \li The character position of the handle. + \row \li \b {styleData.lineHeight} : real \li The height of the line the handle is on. + \endtable + */ + property Component selectionHandle } diff --git a/src/controls/TextArea.qml b/src/controls/TextArea.qml index 1ea265d69..b0c8882f6 100644 --- a/src/controls/TextArea.qml +++ b/src/controls/TextArea.qml @@ -683,7 +683,7 @@ ScrollView { Flickable { id: flickable - interactive: false + interactive: !edit.selectByMouse anchors.fill: parent TextEdit { @@ -739,7 +739,7 @@ ScrollView { wrapMode: TextEdit.WordWrap textMargin: 4 - selectByMouse: Qt.platform.os !== "android" // Workaround for QTBUG-36515 + selectByMouse: !cursorHandle.delegate || !selectionHandle.delegate readOnly: false Keys.forwardTo: area @@ -748,32 +748,139 @@ ScrollView { KeyNavigation.tab: area.tabChangesFocus ? area.KeyNavigation.tab : null KeyNavigation.backtab: area.tabChangesFocus ? area.KeyNavigation.backtab : null - // keep textcursor within scroll view + property bool blockRecursion: false + property bool hasSelection: selectionStart !== selectionEnd + readonly property int selectionPosition: selectionStart !== cursorPosition ? selectionStart : selectionEnd + + // force re-evaluation when contentWidth changes => text layout changes => selection moves + property rect selectionRectangle: contentWidth ? positionToRectangle(selectionPosition) + : positionToRectangle(selectionPosition) + + onSelectionStartChanged: { + if (!blockRecursion && selectionHandle.delegate) { + blockRecursion = true + selectionHandle.position = selectionPosition + blockRecursion = false + } + } + onCursorPositionChanged: { - if (cursorRectangle.y >= flickableItem.contentY + viewport.height - cursorRectangle.height - textMargin) { + if (!blockRecursion && cursorHandle.delegate) { + blockRecursion = true + cursorHandle.position = cursorPosition + blockRecursion = false + } + ensureVisible(cursorRectangle) + } + + function ensureVisible(rect) { + if (rect.y >= flickableItem.contentY + viewport.height - rect.height - textMargin) { // moving down - flickableItem.contentY = cursorRectangle.y - viewport.height + cursorRectangle.height + textMargin - } else if (cursorRectangle.y < flickableItem.contentY) { + flickableItem.contentY = rect.y - viewport.height + rect.height + textMargin + } else if (rect.y < flickableItem.contentY) { // moving up - flickableItem.contentY = cursorRectangle.y - textMargin + flickableItem.contentY = rect.y - textMargin } - if (cursorRectangle.x >= flickableItem.contentX + viewport.width - textMargin) { + if (rect.x >= flickableItem.contentX + viewport.width - textMargin) { // moving right - flickableItem.contentX = cursorRectangle.x - viewport.width + textMargin - } else if (cursorRectangle.x < flickableItem.contentX) { + flickableItem.contentX = rect.x - viewport.width + textMargin + } else if (rect.x < flickableItem.contentX) { // moving left - flickableItem.contentX = cursorRectangle.x - textMargin + flickableItem.contentX = rect.x - textMargin } } + onLinkActivated: area.linkActivated(link) onLinkHovered: area.linkHovered(link) + function activate() { + if (activeFocusOnPress) { + forceActiveFocus() + if (!readOnly) + Qt.inputMethod.show() + } + } + + function moveHandles(cursor, selection) { + blockRecursion = true + Qt.inputMethod.commit() + cursorPosition = cursor + if (selection === -1) { + selectWord() + selection = selectionStart + } + selectionHandle.position = selection + cursorHandle.position = cursorPosition + blockRecursion = false + } + MouseArea { - parent: area.viewport anchors.fill: parent cursorShape: edit.hoveredLink ? Qt.PointingHandCursor : Qt.IBeamCursor - acceptedButtons: Qt.NoButton + acceptedButtons: edit.selectByMouse ? Qt.NoButton : Qt.LeftButton + onClicked: { + var pos = edit.positionAt(mouse.x, mouse.y) + edit.moveHandles(pos, pos) + edit.activate() + } + onPressAndHold: { + var pos = edit.positionAt(mouse.x, mouse.y) + edit.moveHandles(pos, -1) + edit.activate() + } + } + + TextHandle { + id: selectionHandle + + editor: edit + control: area + z: 1 // above scrollbars + parent: __scroller // no clip + delegate: __style.selectionHandle + maximum: cursorHandle.position - 1 + x: edit.selectionRectangle.x - flickableItem.contentX + y: edit.selectionRectangle.y - flickableItem.contentY + visible: pressed || (edit.hasSelection && handleY + handleHeight >= -1 && handleY <= viewport.height + 1 + && handleX + handleWidth >= -1 && handleX <= viewport.width + 1) + + onPositionChanged: { + if (!edit.blockRecursion) { + edit.blockRecursion = true + edit.select(selectionHandle.position, cursorHandle.position) + if (pressed) + edit.ensureVisible(edit.selectionRectangle) + edit.blockRecursion = false + } + } + } + + TextHandle { + id: cursorHandle + + editor: edit + control: area + z: 1 // above scrollbars + parent: __scroller // no clip + delegate: __style.cursorHandle + minimum: edit.hasSelection ? selectionHandle.position + 1 : -1 + x: edit.cursorRectangle.x - flickableItem.contentX + y: edit.cursorRectangle.y - flickableItem.contentY + visible: pressed || ((edit.cursorVisible || edit.hasSelection) + && handleY + handleHeight >= -1 && handleY <= viewport.height + 1 + && handleX + handleWidth >= -1 && handleX <= viewport.width + 1) + + onPositionChanged: { + if (!edit.blockRecursion) { + edit.blockRecursion = true + if (!edit.hasSelection) + selectionHandle.position = cursorHandle.position + Qt.inputMethod.commit() + edit.select(selectionHandle.position, cursorHandle.position) + edit.blockRecursion = false + } + } } } } diff --git a/src/controls/TextField.qml b/src/controls/TextField.qml index a20a5c40c..24f5e5e7f 100644 --- a/src/controls/TextField.qml +++ b/src/controls/TextField.qml @@ -572,14 +572,6 @@ Control { Accessible.role: Accessible.EditableText Accessible.description: placeholderText - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.IBeamCursor - onClicked: textfield.forceActiveFocus() - } - Text { id: placeholderTextComponent anchors.fill: textInput @@ -597,7 +589,7 @@ Control { TextInput { id: textInput focus: true - selectByMouse: Qt.platform.os !== "android" // Workaround for QTBUG-36515 + selectByMouse: !cursorHandle.delegate || !selectionHandle.delegate selectionColor: __panel ? __panel.selectionColor : "darkred" selectedTextColor: __panel ? __panel.selectedTextColor : "white" @@ -624,5 +616,117 @@ Control { } onEditingFinished: textfield.editingFinished() + + property bool blockRecursion: false + property bool hasSelection: selectionStart !== selectionEnd + readonly property int selectionPosition: selectionStart !== cursorPosition ? selectionStart : selectionEnd + + // force re-evaluation when selection moves: + // - cyrsorRectangle changes => content scrolled + // - contentWidth changes => text layout changed + property rect selectionRectangle: cursorRectangle.x && contentWidth ? positionToRectangle(selectionPosition) + : positionToRectangle(selectionPosition) + + onSelectionStartChanged: { + if (!blockRecursion && selectionHandle.delegate) { + blockRecursion = true + selectionHandle.position = selectionPosition + blockRecursion = false + } + } + + onCursorPositionChanged: { + if (!blockRecursion && cursorHandle.delegate) { + blockRecursion = true + cursorHandle.position = cursorPosition + blockRecursion = false + } + } + + function activate() { + if (activeFocusOnPress) { + forceActiveFocus() + if (!readOnly) + Qt.inputMethod.show() + } + } + + function moveHandles(cursor, selection) { + blockRecursion = true + Qt.inputMethod.commit() + cursorPosition = cursor + if (selection === -1) { + selectWord() + selection = selectionStart + } + selectionHandle.position = selection + cursorHandle.position = cursorPosition + blockRecursion = false + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.IBeamCursor + acceptedButtons: textInput.selectByMouse ? Qt.NoButton : Qt.LeftButton + onClicked: { + var pos = textInput.positionAt(mouse.x, mouse.y) + textInput.moveHandles(pos, pos) + textInput.activate() + } + onPressAndHold: { + var pos = textInput.positionAt(mouse.x, mouse.y) + textInput.moveHandles(pos, -1) + textInput.activate() + } + } + + TextHandle { + id: selectionHandle + + editor: textInput + control: textfield + delegate: __style.selectionHandle + maximum: cursorHandle.position - 1 + readonly property real selectionX: textInput.selectionRectangle.x + x: textInput.x + (pressed ? Math.max(0, selectionX) : selectionX) + y: textInput.selectionRectangle.y + textInput.y + visible: pressed || (textInput.hasSelection && handleX + handleWidth >= -1 && handleX <= textfield.width + 1) + + onPositionChanged: { + if (!textInput.blockRecursion) { + textInput.blockRecursion = true + textInput.select(selectionHandle.position, cursorHandle.position) + if (pressed) + textInput.ensureVisible(position) + textInput.blockRecursion = false + } + } + } + + TextHandle { + id: cursorHandle + + editor: textInput + control: textfield + delegate: __style.cursorHandle + minimum: textInput.hasSelection ? selectionHandle.position + 1 : -1 + x: textInput.cursorRectangle.x + textInput.x + y: textInput.cursorRectangle.y + textInput.y + visible: pressed || ((textInput.cursorVisible || textInput.hasSelection) + && handleX + handleWidth >= -1 && handleX <= textfield.width + 1) + + onPositionChanged: { + if (!textInput.blockRecursion) { + textInput.blockRecursion = true + if (!textInput.hasSelection) + selectionHandle.position = cursorHandle.position + Qt.inputMethod.commit() + textInput.select(selectionHandle.position, cursorHandle.position) + textInput.blockRecursion = false + } + } } } diff --git a/tests/manual/texthandles/main.cpp b/tests/manual/texthandles/main.cpp new file mode 100644 index 000000000..210d777ec --- /dev/null +++ b/tests/manual/texthandles/main.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QGuiApplication> +#include <QQmlApplicationEngine> + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + QQmlApplicationEngine engine(QUrl("qrc:/main.qml")); + return app.exec(); +} diff --git a/tests/manual/texthandles/main.qml b/tests/manual/texthandles/main.qml new file mode 100644 index 000000000..e5b8b3db1 --- /dev/null +++ b/tests/manual/texthandles/main.qml @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +import QtQuick 2.1 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 + +ApplicationWindow { + id: window + + width: 800 + height: 480 + visible: true + + toolBar: ToolBar { + RowLayout { + anchors.fill: parent + anchors.margins: window.spacing + CheckBox { + id: handleBox + text: "Handles" + checked: true + } + CheckBox { + id: outlineBox + text: "Outlines" + checked: false + enabled: handleBox.checked + } + Item { width: 1; height: 1; Layout.fillWidth: true } + CheckBox { + id: wrapBox + text: "Wrap" + checked: true + } + } + } + + property int spacing: edit.font.pixelSize / 2 + + property string loremIpsum: "Lorem ipsum dolor sit amet, <a href='http://qt.digia.com'>consectetur</a> adipiscing elit. " + + "Morbi varius a lorem ac blandit. Donec eu nisl eu nisi consectetur commodo. " + + "Vestibulum tincidunt <img src='http://qt.digia.com/Static/Images/QtLogo.png'>ornare</img> tempor. " + + "Nulla dolor dui, vehicula quis tempor quis, ullamcorper vel dui. " + + "Integer semper suscipit ante, et luctus magna malesuada sed. " + + "Sed ipsum velit, pellentesque non aliquam eu, bibendum ac magna. " + + "Donec et luctus dolor. Nulla semper quis neque vitae cursus. " + + "Etiam auctor, ipsum vel varius tincidunt, erat lacus pulvinar sem, eu egestas leo nulla non felis. " + + "Maecenas hendrerit commodo turpis, ac convallis leo congue id. " + + "Donec et egestas ante, a dictum sapien." + + ColumnLayout { + spacing: window.spacing + anchors.margins: window.spacing + anchors.fill: parent + + TextField { + id: field + z: 1 + text: loremIpsum + Layout.fillWidth: true + + style: TextFieldStyle { + cursorHandle: handleBox.checked ? cursorDelegate : null + selectionHandle: handleBox.checked ? selectionDelegate : null + } + } + + TextArea { + id: edit + Layout.fillWidth: true + Layout.fillHeight: true + + textFormat: Qt.RichText + wrapMode: wrapBox.checked ? Text.Wrap : Text.NoWrap + text: loremIpsum + "<p>" + loremIpsum + "<p>" + loremIpsum + "<p>" + loremIpsum + + style: TextAreaStyle { + cursorHandle: handleBox.checked ? cursorDelegate : null + selectionHandle: handleBox.checked ? selectionDelegate : null + } + } + } + + Component { + id: selectionDelegate + Rectangle { + x: -width + edit.font.pixelSize / 2 + y: (styleData.lineHeight - height) / 2 + width: edit.font.pixelSize * 2.5 + height: edit.font.pixelSize * 2.5 + border.width: outlineBox.checked ? 1 : 0 + radius: width / 4 + color: "transparent" + Rectangle { + color: "white" + border.width: 1 + radius: width / 2 + width: height + height: edit.font.pixelSize / 2 + anchors.right: parent.right + anchors.rightMargin: width / 2 + anchors.verticalCenter: parent.verticalCenter + visible: control.activeFocus && control.selectionStart !== control.selectionEnd + } + } + } + + Component { + id: cursorDelegate + Rectangle { + x: control.selectionStart !== control.selectionEnd ? -edit.font.pixelSize / 2 : -width / 2 + y: (styleData.lineHeight - height) / 2 + width: edit.font.pixelSize * 2.5 + height: edit.font.pixelSize * 2.5 + border.width: outlineBox.checked ? 1 : 0 + radius: width / 4 + color: "transparent" + Rectangle { + color: "white" + border.width: 1 + radius: width / 2 + width: height + height: edit.font.pixelSize / 2 + anchors.left: parent.left + anchors.leftMargin: width / 2 + anchors.verticalCenter: parent.verticalCenter + visible: control.activeFocus && control.selectionStart !== control.selectionEnd + } + } + } +} diff --git a/tests/manual/texthandles/texthandles.pro b/tests/manual/texthandles/texthandles.pro new file mode 100644 index 000000000..0c7c00d84 --- /dev/null +++ b/tests/manual/texthandles/texthandles.pro @@ -0,0 +1,11 @@ +TARGET = texthandles +QT += qml quick + +SOURCES += \ + $$PWD/main.cpp + +OTHER_FILES += \ + $$PWD/main.qml + +RESOURCES += \ + texthandles.qrc diff --git a/tests/manual/texthandles/texthandles.qmlproject b/tests/manual/texthandles/texthandles.qmlproject new file mode 100644 index 000000000..e5a8bf02c --- /dev/null +++ b/tests/manual/texthandles/texthandles.qmlproject @@ -0,0 +1,16 @@ +import QmlProject 1.1 + +Project { + mainFile: "main.qml" + + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "." + } + JavaScriptFiles { + directory: "." + } + ImageFiles { + directory: "." + } +} diff --git a/tests/manual/texthandles/texthandles.qrc b/tests/manual/texthandles/texthandles.qrc new file mode 100644 index 000000000..5f6483ac3 --- /dev/null +++ b/tests/manual/texthandles/texthandles.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>main.qml</file> + </qresource> +</RCC> |
