X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=mardrone%2Fimports%2Fcom%2Fnokia%2Fandroid.1.1%2FTextArea.qml;fp=mardrone%2Fimports%2Fcom%2Fnokia%2Fandroid.1.1%2FTextArea.qml;h=cb7ba8851fe7635ea8a86cf88c16a8b5af22591a;hb=423f5226eddc5c327ef47559c03b0e2775add19e;hp=0000000000000000000000000000000000000000;hpb=c6326414c8585a359a4278f028042dfb4c0a749e;p=mardrone diff --git a/mardrone/imports/com/nokia/android.1.1/TextArea.qml b/mardrone/imports/com/nokia/android.1.1/TextArea.qml new file mode 100644 index 0000000..cb7ba88 --- /dev/null +++ b/mardrone/imports/com/nokia/android.1.1/TextArea.qml @@ -0,0 +1,417 @@ +/**************************************************************************** +** +** 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 Qt Components project. +** +** $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 Nokia Corporation 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 1.1 +import "." 1.1 + +FocusScopeItem { + id: root + + // Common public API + property alias font: textEdit.font + property alias cursorPosition: textEdit.cursorPosition + property alias horizontalAlignment: textEdit.horizontalAlignment + property alias inputMethodHints: textEdit.inputMethodHints + property alias verticalAlignment: textEdit.verticalAlignment + property alias readOnly: textEdit.readOnly + property alias selectedText: textEdit.selectedText + property alias selectionEnd: textEdit.selectionEnd + property alias selectionStart: textEdit.selectionStart + property alias text: textEdit.text + property alias textFormat: textEdit.textFormat + property alias wrapMode: textEdit.wrapMode + property bool errorHighlight: false + + function copy() { + textEdit.copy() + } + + function paste() { + textEdit.paste() + } + + function cut() { + textEdit.cut() + } + + function select(start, end) { + textEdit.select(start, end) + } + + function selectAll() { + textEdit.selectAll() + } + + function selectWord() { + textEdit.selectWord() + } + + function positionAt(x, y) { + var p = mapToItem(textEdit, x, y); + return textEdit.positionAt(p.x, p.y) + } + + function positionToRectangle(pos) { + var rect = textEdit.positionToRectangle(pos) + var point = mapFromItem(textEdit, rect.x, rect.y) + rect.x = point.x; rect.y = point.y + return rect; + } + + function openSoftwareInputPanel() { + textEdit.openSoftwareInputPanel() + } + + function closeSoftwareInputPanel() { + textEdit.closeSoftwareInputPanel() + } + + // API extensions + property alias placeholderText: placeholder.text + // TODO: Refactor implicit size when following bugs are resolved + // http://bugreports.qt.nokia.com/browse/QTBUG-14957 + // http://bugreports.qt.nokia.com/browse/QTBUG-16665 + // http://bugreports.qt.nokia.com/browse/QTBUG-16710 (fixed in Qt 4.7.2) + // http://bugreports.qt.nokia.com/browse/QTBUG-12305 (fixed in QtQuick1.1) + property real platformMaxImplicitWidth: -1 + property real platformMaxImplicitHeight: -1 + property bool platformInverted: false + property bool enabled: true // overriding due to QTBUG-15797 and related bugs + + implicitWidth: { + var preferredWidth = placeholder.visible ? placeholder.model.paintedWidth + : flick.contentWidth + preferredWidth = Math.max(preferredWidth, privy.minImplicitWidth) + preferredWidth += container.horizontalMargins + if (root.platformMaxImplicitWidth >= 0) + return Math.min(preferredWidth, root.platformMaxImplicitWidth) + return preferredWidth + } + + implicitHeight: { + var preferredHeight = placeholder.visible ? placeholder.model.paintedHeight + : flick.contentHeight + preferredHeight += container.verticalMargins + // layout spec gives minimum height (textFieldHeight) which includes required padding + preferredHeight = Math.max(privateStyle.textFieldHeight, preferredHeight) + if (root.platformMaxImplicitHeight >= 0) + return Math.min(preferredHeight, root.platformMaxImplicitHeight) + return preferredHeight + } + + onWidthChanged: { + // Detect when a width has been explicitly set. Needed to determine if the TextEdit should + // grow horizontally or wrap. I.e. in determining the model's width. There's no way to get + // notified of having an explicit width set. Therefore it's polled in widthChanged. + privy.widthExplicit = root.widthExplicit() + } + + Connections { + target: screen + onCurrentOrientationChanged: { + delayedEnsureVisible.start() + fade.start() + scroll.start() + } + } + + QtObject { + id: privy + // TODO: More consistent minimum width for empty TextArea than 20 * " " on current font? + property real minImplicitWidth: privateStyle.textWidth(" ", textEdit.font) + property bool widthExplicit: false + property bool wrap: privy.widthExplicit || root.platformMaxImplicitWidth >= 0 + property real wrapWidth: privy.widthExplicit ? root.width - container.horizontalMargins + : root.platformMaxImplicitWidth - container.horizontalMargins + function bg_postfix() { + if (root.errorHighlight) + return "error" + else if (root.readOnly || !root.enabled) + return "uneditable" + else if (textEdit.activeFocus) + return "highlighted" + else + return "editable" + } + } + + BorderImage { + id: background + anchors.fill: parent + source: privateStyle.imagePath("qtg_fr_textfield_" + privy.bg_postfix(), root.platformInverted) + border { + left: platformStyle.borderSizeMedium + top: platformStyle.borderSizeMedium + right: platformStyle.borderSizeMedium + bottom: platformStyle.borderSizeMedium + } + smooth: true + } + + Item { + id: container + + property real horizontalMargins: container.anchors.leftMargin + + container.anchors.rightMargin + + flick.anchors.leftMargin + + flick.anchors.rightMargin + + property real verticalMargins: container.anchors.topMargin + + container.anchors.bottomMargin + + flick.anchors.topMargin + + flick.anchors.bottomMargin + + anchors { + fill: parent + leftMargin: platformStyle.paddingSmall; rightMargin: platformStyle.paddingSmall + topMargin: platformStyle.paddingMedium; bottomMargin: platformStyle.paddingMedium + } + + clip: true + + // TODO: Should placeholder also be scrollable? + Text { + id: placeholder + objectName: "placeholder" + + // TODO: See TODO: Refactor implicit size... + property variant model: Text { + font: textEdit.font + text: placeholder.text + visible: false + wrapMode: textEdit.wrapMode + horizontalAlignment: textEdit.horizontalAlignment + verticalAlignment: textEdit.verticalAlignment + opacity: 0 + + Binding { + when: privy.wrap + target: placeholder.model + property: "width" + value: privy.wrapWidth + } + } + + color: root.platformInverted ? platformStyle.colorNormalMidInverted + : platformStyle.colorNormalMid + font: textEdit.font + horizontalAlignment: textEdit.horizontalAlignment + verticalAlignment: textEdit.verticalAlignment + visible: { + if (text && (textEdit.model.paintedWidth == 0 && textEdit.model.paintedHeight <= textEdit.cursorRectangle.height)) + return (readOnly || !textEdit.activeFocus) + else + return false + } + wrapMode: textEdit.wrapMode + x: flick.x; y: flick.y + height: flick.height; width: flick.width + } + + Flickable { + id: flick + + property real tiny: Math.round(platformStyle.borderSizeMedium / 2) + + function ensureVisible(rect) { + if (Math.round(contentX) > Math.round(rect.x)) + contentX = rect.x + else if (Math.round(contentX + width) < Math.round(rect.x + rect.width)) + contentX = rect.x + rect.width - width + + if (Math.round(contentY) > Math.round(rect.y)) + contentY = rect.y + else if (Math.round(contentY + height) < Math.round(rect.y + rect.height)) + contentY = rect.y + rect.height - height + } + + anchors { + fill: parent + leftMargin: tiny + rightMargin: tiny + topMargin: tiny / 2 + bottomMargin: tiny / 2 + } + + boundsBehavior: Flickable.StopAtBounds + contentHeight: textEdit.model.paintedHeight + contentWidth: textEdit.model.paintedWidth + + (textEdit.wrapMode == TextEdit.NoWrap ? textEdit.cursorRectangle.width : 0) + interactive: root.enabled + + onHeightChanged: { + if(textEdit.cursorVisible || textEdit.cursorPosition == textEdit.selectionEnd) + ensureVisible(textEdit.cursorRectangle) + } + + onWidthChanged: { + if(textEdit.cursorVisible || textEdit.cursorPosition == textEdit.selectionEnd) + ensureVisible(textEdit.cursorRectangle) + } + + TextEdit { + id: textEdit + objectName: "textEdit" + + // TODO: See TODO: Refactor implicit size... + property variant model: TextEdit { + font: textEdit.font + text: textEdit.text + horizontalAlignment: textEdit.horizontalAlignment + verticalAlignment: textEdit.verticalAlignment + wrapMode: textEdit.wrapMode + visible: false + opacity: 0 + + // In Wrap mode, if the width is bound the text will always get wrapped at the + // set width. If the width is not bound the text won't get wrapped but + // paintedWidth will increase. + Binding { + when: privy.wrap + target: textEdit.model + property: "width" + value: privy.wrapWidth + } + } + activeFocusOnPress: false + enabled: root.enabled + focus: true + font { family: platformStyle.fontFamilyRegular; pixelSize: platformStyle.fontSizeMedium } + color: root.platformInverted ? platformStyle.colorNormalLightInverted + : platformStyle.colorNormalDark + cursorVisible: activeFocus && !selectedText + selectedTextColor: root.platformInverted ? platformStyle.colorNormalDarkInverted + : platformStyle.colorNormalLight + selectionColor: root.platformInverted ? platformStyle.colorTextSelectionInverted + : platformStyle.colorTextSelection + textFormat: TextEdit.AutoText + wrapMode: TextEdit.Wrap + height: flick.height + width: flick.width + // TODO: Make bug report? + // Called too early (before TextEdit size is adjusted) delay ensureVisible call a bit + onCursorRectangleChanged: delayedEnsureVisible.start() + onActiveFocusChanged: { + if (activeFocus) { + horizontal.flash() + vertical.flash() + } + } + onEnabledChanged: { + if (!enabled) { + deselect() + // De-focusing requires setting focus elsewhere, in this case editor's parent + if (root.parent) + root.parent.forceActiveFocus() + } + } + + Keys.forwardTo: touchController + + TextTouchController { + id: touchController + + // selection handles require touch area geometry to differ from TextEdit's geometry + anchors { + top: editor.top; topMargin: -container.verticalMargins / 2 + left: editor.left; leftMargin: -container.horizontalMargins / 2 + } + height: Math.max(root.height, flick.contentHeight + container.verticalMargins * 2) + width: Math.max(root.width, flick.contentWidth + container.horizontalMargins * 2) + editorScrolledX: flick.contentX - (container.horizontalMargins / 2) + editorScrolledY: flick.contentY - (container.verticalMargins / 2) + copyEnabled: textEdit.selectedText + cutEnabled: !textEdit.readOnly && textEdit.selectedText + platformInverted: root.platformInverted + Component.onCompleted: flick.movementEnded.connect(touchController.flickEnded) + Connections { target: screen; onCurrentOrientationChanged: touchController.updateGeometry() } + Connections { + target: textEdit + onHeightChanged: touchController.updateGeometry() + onWidthChanged: touchController.updateGeometry() + onHorizontalAlignmentChanged: touchController.updateGeometry() + onVerticalAlignmentChanged: touchController.updateGeometry() + onWrapModeChanged: touchController.updateGeometry() + onFontChanged: touchController.updateGeometry() + } + } + } + + PropertyAnimation { id: fade; target: textEdit; property: "opacity"; from: 0; to: 1; duration: 250 } + PropertyAnimation { id: scroll; target: flick; property: "contentY"; duration: 250 } + } + + ScrollBar { + id: vertical + anchors { + top: flick.top; + topMargin: -flick.tiny / 2; + left: flick.right; + } + flickableItem: flick + interactive: false + orientation: Qt.Vertical + height: container.height + platformInverted: root.platformInverted + } + + ScrollBar { + id: horizontal + anchors { + left: flick.left; + leftMargin: -flick.tiny; + bottom: container.bottom; + bottomMargin: -flick.tiny / 2 + rightMargin: vertical.opacity ? vertical.width : 0 + } + flickableItem: flick + interactive: false + orientation: Qt.Horizontal + width: container.width + platformInverted: root.platformInverted + } + + Timer { + id: delayedEnsureVisible + interval: 1 + onTriggered: flick.ensureVisible(textEdit.cursorRectangle) + } + } +}