Hey, I've worked on the editing features in the Plasma QML Components in kde- runtime, with some pretty good success. You can find the results in kde- runtime's sebas/editbubble branch.
The patches add -- nomen est omen -- an edit bubble to the touch version of the Plasma Components, which allow for basic copy and paste. Triggering is done on pressAndHold, the bubble moves with the cursor, so it's pretty basic but working quite well. (It allows the user for example to copy and paste in the URL bar. Obviously, this only works for our TextField and TextArea, so QWidgets are left out, and every other (QML) Text input should be ported to use Plasma Components. For Plasma Active, I think this is quite important functionality, so I suggest that we ship this patch (or an improved version of it) with PA2, and then integrate it into kde-runtime master at the start of the next cycle. The patch adds a MouseEventListener which is basically a MouseArea which does *not* intercept events (the normal MouseArea does, and it's not changable, so we pretty much have to do it this way). This guy moves from mobilecomponents into qtextra. Note: This does not entail selection / editing for Text elements, or the webview itself. This is a larger issue, that we can still tackle once we're happy with this basic version. Cheers, -- sebas http://www.kde.org | http://vizZzion.org | GPG Key ID: 9119 0EF9
diff --git a/plasma/declarativeimports/plasmacomponents/CMakeLists.txt b/plasma/declarativeimports/plasmacomponents/CMakeLists.txt index 8af2dfa..bb43f9c 100644 --- a/plasma/declarativeimports/plasmacomponents/CMakeLists.txt +++ b/plasma/declarativeimports/plasmacomponents/CMakeLists.txt @@ -63,8 +63,8 @@ install(FILES qml/TabBar.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/t install(FILES qml/TabButton.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components) install(FILES qml/TabGroup.js DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components) install(FILES qml/TabGroup.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components) -install(FILES qml/TextArea.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components) -install(FILES qml/TextField.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components) +#install(FILES qml/TextArea.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components) +#install(FILES qml/TextField.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components) install(FILES qml/ToolBarLayout.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components) install(FILES qml/ToolBar.qml DESTINATION ${PLUGIN_INSTALL_DIR}/platformimports/touch/org/kde/plasma/components) diff --git a/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/EditBubble.js b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/EditBubble.js new file mode 100644 index 0000000..a8ad3ae --- /dev/null +++ b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/EditBubble.js @@ -0,0 +1,23 @@ +function placeEditBubble(mouse) { + // Find the root item, then map our cursor position to it + // in order to check if the edit bubble could end up off-screen + var rootItem = parent; + while (rootItem.parent) { + rootItem = rootItem.parent; + } + var distanceToTop = mouseEventListener.mapToItem(rootItem, mouse.x, mouse.y); + print( " distanceToTop: " + distanceToTop.x); + if (distanceToTop.x < editBubble.width/2) { + // hitting the left edge + //editBubble.x = mouse.x + + } else { + editBubble.x = mouse.x-(editBubble.width/2) + } + if (distanceToTop.y > editBubble.height) { + editBubble.y = mouse.y-editBubble.height-8 + } else { + //editBubble.y = mouse.y-(editBubble.width/2) + } + +} diff --git a/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/EditBubble.qml b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/EditBubble.qml new file mode 100644 index 0000000..96ca25e --- /dev/null +++ b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/EditBubble.qml @@ -0,0 +1,109 @@ +/* +* Copyright 2011 by Sebastian Kügler <se...@kde.org> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import QtQuick 1.1 +import org.kde.plasma.core 0.1 as PlasmaCore +import org.kde.qtextracomponents 0.1 + +PlasmaCore.FrameSvgItem { + id: editBubble + objectName: "editBubble" + property int iconSize: 32; + + imagePath: "dialogs/background" + width: (iconSize*2) + iconSize + height: iconSize*2 + z: 100000 + //anchors { top: parent.bottom; right: parent.right; topMargin: -(iconSize/4); } + + // fully dynamic show / hide + //state: (textInput.activeFocus && (textInput.selectedText != "" || textInput.canPaste)) ? "expanded" : "collapsed"; + // state controlled externally + state: "collapsed" + + Row { + id: buttonRow + spacing: 4 + anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter; margins: 8; } + height: editBubble.iconSize + QIconItem { + id: pasteIcon + icon: QIcon("edit-paste") + width: editBubble.iconSize + height: editBubble.iconSize + enabled: textInput.canPaste + MouseArea { + anchors.fill: parent; + onClicked: { textField.paste(); editBubble.state = "collapsed"; } + onPressed: PropertyAnimation { target: pasteIcon; properties: "scale"; + from: 1.0; to: 0.9; + duration: 175; easing.type: Easing.OutExpo; } + onReleased: PropertyAnimation { target: pasteIcon; properties: "scale"; + from: 0.9; to: 1.0; + duration: 175; easing.type: Easing.OutExpo; } + } + } + QIconItem { + id: copyIcon + icon: QIcon("edit-copy") + width: editBubble.iconSize + height: editBubble.iconSize + enabled: textInput.selectedText != "" + MouseArea { + anchors.fill: parent; + onClicked: { textField.copy(); editBubble.state = "collapsed"; } + onPressed: PropertyAnimation { target: copyIcon; properties: "scale"; + from: 1.0; to: 0.9; + duration: 175; easing.type: Easing.OutExpo; } + onReleased: PropertyAnimation { target: copyIcon; properties: "scale"; + from: 0.9; to: 1.0; + duration: 175; easing.type: Easing.OutExpo; } + } + } + } + states: [ + State { + id: expanded + name: "expanded"; + PropertyChanges { target: editBubble; opacity: 1.0; scale: 1.0 } + }, + State { + id: collapsed + name: "collapsed"; + PropertyChanges { target: editBubble; opacity: 0; scale: 0.9 } + } + ] + + transitions: [ + Transition { + from: "collapsed"; to: "expanded" + ParallelAnimation { + PropertyAnimation { properties: "opacity"; duration: 175; easing.type: Easing.InExpo; } + PropertyAnimation { properties: "scale"; duration: 175; easing.type: Easing.InExpo; } + } + }, + Transition { + from: "expanded"; to: "collapsed" + ParallelAnimation { + PropertyAnimation { properties: "opacity"; duration: 175; easing.type: Easing.OutExpo; } + PropertyAnimation { properties: "scale"; duration: 100; easing.type: Easing.OutExpo; } + } + } + ] +} diff --git a/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/TextArea.qml b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/TextArea.qml new file mode 100644 index 0000000..71e14ca --- /dev/null +++ b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/TextArea.qml @@ -0,0 +1,247 @@ +/* +* Copyright (C) 2011 by Daker Fernandes Pinheiro <dake...@gmail.com> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import QtQuick 1.1 +import org.kde.plasma.core 0.1 as PlasmaCore +import org.kde.qtextracomponents 0.1 +import "EditBubble.js" as EditBubbleHelper + +Item { + id: textArea + + // Common API + property alias font: textEdit.font // alias to textEdit.font + property int inputMethodHints + property bool errorHighlight + property alias cursorPosition: textEdit.cursorPosition + property alias horizontalAlignment: textEdit.cursorPosition + property alias verticalAlignment: textEdit.cursorPosition + property alias readOnly: textEdit.readOnly + property alias selectedText: textEdit.selectedText // read-only + property alias selectionEnd: textEdit.selectionEnd // read-only + property alias selectionStart: textEdit.selectionStart // read-only + property alias text: textEdit.text + property alias textFormat: textEdit.textFormat // enumeration + property alias wrapMode: textEdit.wrapMode // enumeration + property string placeholderText + + property alias textField: textArea + + // functions + 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(pos) { + textEdit.positionAt(pos); + } + + function positionToRectangle(pos) { + textEdit.positionToRectangle(pos); + } + + // Plasma API + property alias interactive: flickArea.interactive + property alias contentMaxWidth: textEdit.width + property alias contentMaxHeight: textEdit.height + property alias textInput: textEdit + + // Set active focus to it's internal textInput. + // Overriding QtQuick.Item forceActiveFocus function. + function forceActiveFocus() { + textEdit.forceActiveFocus(); + } + + // Overriding QtQuick.Item activeFocus property. + property alias activeFocus: textEdit.activeFocus + + opacity: enabled ? 1.0 : 0.5 + + TextFieldFocus { + id: hover + state: textArea.activeFocus ? "focus" : (mouseWatcher.containsMouse ? "hover" : "hidden") + anchors.fill: base + } + + MouseArea { + id: mouseWatcher + anchors.fill: hover + hoverEnabled: true + } + + PlasmaCore.FrameSvgItem { + id: base + + // TODO: see what is the best policy for margins + anchors { + fill: parent + } + imagePath: "widgets/lineedit" + prefix: "base" + } + + Flickable { + id: flickArea + anchors { + fill: parent + leftMargin: 2 * base.margins.left + rightMargin: 2 * base.margins.right + (verticalScroll.visible ? verticalScroll.width : 0) + topMargin: 2 * base.margins.top + bottomMargin: 2 * base.margins.bottom + (horizontalScroll.visible ? verticalScroll.width : 0) + } + interactive: !verticalScroll.interactive //textArea.activeFocus + contentWidth: { + if (textEdit.wrapMode == TextEdit.NoWrap) + return textEdit.paintedWidth; + + return Math.min(textEdit.paintedWidth, textEdit.width); + } + contentHeight: Math.min(textEdit.paintedHeight, textEdit.height) + clip: true + MouseEventListener { + id: mouseEventListener + //anchors.fill: parent + onPressed: forceActiveFocus(); + //onPressed: print(" MouseEventListener Pressed"); + onPressAndHold: { + print(" *** MouseEventListener PressAndHold"); + //forceActiveFocus(); + EditBubbleHelper.placeEditBubble(mouse); + editBubble.state = (textInput.activeFocus && (textInput.selectedText != "" || textInput.canPaste)) ? "expanded" : "collapsed"; + } + onPositionChanged: { + EditBubbleHelper.placeEditBubble(mouse); + } + } + + TextEdit { + id: textEdit + parent: mouseEventListener + width: flickArea.width + height: flickArea.height + clip: true + wrapMode: TextEdit.Wrap + enabled: textArea.enabled + font.capitalization: theme.defaultFont.capitalization + font.family: theme.defaultFont.family + font.italic: theme.defaultFont.italic + font.letterSpacing: theme.defaultFont.letterSpacing + font.pointSize: theme.defaultFont.pointSize + font.strikeout: theme.defaultFont.strikeout + font.underline: theme.defaultFont.underline + font.weight: theme.defaultFont.weight + font.wordSpacing: theme.defaultFont.wordSpacing + color: theme.viewTextColor + selectByMouse: verticalScroll.interactive + + onCursorPositionChanged: { + if (cursorRectangle.x < flickArea.contentX) { + flickArea.contentX = cursorRectangle.x; + return; + } + + if (cursorRectangle.x > flickArea.contentX + + flickArea.width - cursorRectangle.width) { + flickArea.contentX = cursorRectangle.x - + cursorRectangle.width; + return; + } + + if (cursorRectangle.y < flickArea.contentY) { + flickArea.contentY = cursorRectangle.y; + return; + } + + if (cursorRectangle.y > flickArea.contentY + + flickArea.height - cursorRectangle.height) { + flickArea.contentY = cursorRectangle.y - + cursorRectangle.height; + return; + } + } + + // Proxying keys events is not required by the + // common API but is desired in the plasma API. + Keys.onPressed: textArea.Keys.pressed(event); + Keys.onReleased: textArea.Keys.released(event); + + Text { + anchors.fill: parent + text: textArea.placeholderText + visible: textEdit.text == "" && !textArea.activeFocus + opacity: 0.5 + } + } + } + + ScrollBar { + id: horizontalScroll + anchors { + bottom: parent.bottom + left: parent.left + right: flickArea.right + } + enabled: parent.enabled + flickableItem: flickArea + orientation: Qt.Horizontal + stepSize: textEdit.font.pixelSize + } + + ScrollBar { + id: verticalScroll + anchors { + right: parent.right + top: parent.top + bottom: flickArea.bottom + } + enabled: parent.enabled + flickableItem: flickArea + orientation: Qt.Vertical + stepSize: textEdit.font.pixelSize + } + + EditBubble { id: editBubble; iconSize: 32; } + + onActiveFocusChanged: { + if (!activeFocus) { + editBubble.state = "collapsed"; + //print("Hiding..."); + } + } +} \ No newline at end of file diff --git a/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/TextField.qml b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/TextField.qml new file mode 100644 index 0000000..daa54ea --- /dev/null +++ b/plasma/declarativeimports/plasmacomponents/platformcomponents/touch/TextField.qml @@ -0,0 +1,216 @@ +/* +* Copyright (C) 2011 by Daker Fernandes Pinheiro <dake...@gmail.com> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import QtQuick 1.1 +import org.kde.plasma.core 0.1 as PlasmaCore +import org.kde.qtextracomponents 0.1 +import "EditBubble.js" as EditBubbleHelper + +Item { + id: textField + + // Common API + property bool errorHighlight: false // TODO + property string placeholderText + property alias inputMethodHints: textInput.inputMethodHints + property alias font: textInput.font + + property alias cursorPosition: textInput.cursorPosition + property alias readOnly: textInput.readOnly + property alias echoMode: textInput.echoMode // Supports TextInput.Normal,TextInput.Password, TextInput.NoEcho, TextInput.PasswordEchoOnEdit + property alias acceptableInput: textInput.acceptableInput // read-only + property alias inputMask: textInput.inputMask + property alias validator: textInput.validator + property alias selectedText: textInput.selectedText // read-only + property alias selectionEnd: textInput.selectionEnd // read-only + property alias selectionStart: textInput.selectionStart // read-only + property alias text: textInput.text + property alias maximumLength: textInput.maximumLength + + //Plasma api + property bool clearButtonShown: false + + function copy() { + textInput.copy(); + } + + function paste() { + textInput.paste(); + } + + function cut() { + textInput.cut(); + } + + function select(start, end) { + textInput.select(start, end); + } + + function selectAll() { + textInput.selectAll(); + } + + function selectWord() { + textInput.selectWord(); + } + + function positionAt(pos) { + textInput.positionAt(pos); + } + + function positionToRectangle(pos) { + textInput.positionToRectangle(pos); + } + + + // Set active focus to it's internal textInput. + // Overriding QtQuick.Item forceActiveFocus function. + function forceActiveFocus() { + textInput.forceActiveFocus(); + } + + // Overriding QtQuick.Item activeFocus property. + property alias activeFocus: textInput.activeFocus + + // TODO: fix default size + implicitWidth: theme.defaultFont.mSize.width*12 + implicitHeight: theme.defaultFont.mSize.height*1.6 + // TODO: needs to define if there will be specific graphics for + // disabled text fields + opacity: enabled ? 1.0 : 0.5 + + TextFieldFocus { + id: hover + state: textInput.activeFocus ? "focus" : (mouseWatcher.containsMouse ? "hover" : "hidden") + anchors.fill: base + } + + PlasmaCore.FrameSvgItem { + id: base + + // TODO: see what is the correct policy for margins + anchors.fill: parent + imagePath: "widgets/lineedit" + prefix: "base" + } + + MouseArea { + id: mouseWatcher + anchors.fill: hover + hoverEnabled: false + } + + Text { + anchors { + left: parent.left + right: parent.right + verticalCenter: parent.verticalCenter + leftMargin: 2 * base.margins.left + rightMargin: 2 * base.margins.right + } + text: placeholderText + visible: textInput.text == "" && !textField.activeFocus + // XXX: using textColor and low opacity for theming placeholderText + color: theme.viewTextColor + opacity: 0.5 + elide: Text.ElideRight + clip: true + font.capitalization: theme.defaultFont.capitalization + font.family: theme.defaultFont.family + font.italic: theme.defaultFont.italic + font.letterSpacing: theme.defaultFont.letterSpacing + font.pointSize: theme.defaultFont.pointSize + font.strikeout: theme.defaultFont.strikeout + font.underline: theme.defaultFont.underline + font.weight: theme.defaultFont.weight + font.wordSpacing: theme.defaultFont.wordSpacing + + } + + EditBubble { id: editBubble; iconSize: 32 } + + TextInput { + id: textInput + parent: mouseEventListener + + anchors { + left: parent.left + right: parent.right + verticalCenter: parent.verticalCenter + // TODO: see what is the correct policy for margins + leftMargin: 2 * base.margins.left + rightMargin: 2 * base.margins.right + } + selectByMouse: true + color: theme.textColor + enabled: textField.enabled + clip: true + + // Proxying keys events is not required by the + // common API but is desired in the plasma API. + Keys.onPressed: textField.Keys.pressed(event); + Keys.onReleased: textField.Keys.released(event); + } + + PlasmaCore.SvgItem { + parent: mouseEventListener // reparent to the MouseFilter for MouseArea to work + svg: PlasmaCore.Svg {imagePath: "widgets/lineedit"} + elementId: "clearbutton" + width: textInput.height + height: textInput.height + opacity: (textInput.text != "" && clearButtonShown) ? 1 : 0 + Behavior on opacity { + NumberAnimation { + duration: 250 + easing.type: Easing.InOutQuad + } + } + anchors { + right: parent.right + rightMargin: y + verticalCenter: parent.verticalCenter + } + MouseArea { + anchors.fill: parent + onClicked: { + textInput.text = ""; + textInput.forceActiveFocus(); + editBubble.state = "collapsed" + } + } + } + + MouseEventListener { + id: mouseEventListener + anchors.fill: parent + onPressAndHold: { + EditBubbleHelper.placeEditBubble(mouse); + editBubble.state = (textInput.activeFocus && (textInput.selectedText != "" || textInput.canPaste)) ? "expanded" : "collapsed"; + } + onPositionChanged: { + EditBubbleHelper.placeEditBubble(mouse); + } + } + + onActiveFocusChanged: { + if (!activeFocus) { + editBubble.state = "collapsed"; + } + } +} \ No newline at end of file diff --git a/plasma/declarativeimports/qtextracomponents/CMakeLists.txt b/plasma/declarativeimports/qtextracomponents/CMakeLists.txt index a78644f..05a1195 100644 --- a/plasma/declarativeimports/qtextracomponents/CMakeLists.txt +++ b/plasma/declarativeimports/qtextracomponents/CMakeLists.txt @@ -7,6 +7,7 @@ set(qtextracomponents_SRCS qpixmapitem.cpp qimageitem.cpp qiconitem.cpp + mouseeventlistener.cpp ) INCLUDE_DIRECTORIES( diff --git a/plasma/declarativeimports/qtextracomponents/mouseeventlistener.cpp b/plasma/declarativeimports/qtextracomponents/mouseeventlistener.cpp new file mode 100644 index 0000000..3b9222f --- /dev/null +++ b/plasma/declarativeimports/qtextracomponents/mouseeventlistener.cpp @@ -0,0 +1,134 @@ +/* + Copyright 2011 Marco Martin <notm...@gmail.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "mouseeventlistener.h" + +#include <QEvent> +#include <QGraphicsSceneMouseEvent> +#include <QtCore/QTimer> + +#include <KDebug> + +MouseEventListener::MouseEventListener(QDeclarativeItem *parent) + : QDeclarativeItem(parent), + m_pressed(false), + m_pressAndHoldEvent(0) +{ + setFiltersChildEvents(true); + setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton|Qt::MidButton|Qt::XButton1|Qt::XButton2); +} + +MouseEventListener::~MouseEventListener() +{ +} + +void MouseEventListener::mousePressEvent(QGraphicsSceneMouseEvent *me) +{ + //FIXME: when a popup window is visible: a click anywhere hides it: but the old qgraphicswidget will continue to think it's under the mouse + //doesn't seem to be any good way to properly reset this. + //this msolution will still caused a missed click after the popup is gone, but gets the situation unblocked. + if (!isUnderMouse()) { + me->ignore(); + return; + } + + QDeclarativeMouseEvent dme(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers()); + m_pressAndHoldEvent = new QDeclarativeMouseEvent(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers()); + kDebug() << "pressed in mousePressEvent"; + emit pressed(&dme); + m_pressed = true; + //delete m_pressAndHoldEvent; + //m_pressAndHoldEvent = &dme; + //new QDeclarativeMouseEvent(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers());; + QTimer::singleShot(800, this, SLOT(handlePressAndHold())); +} + +void MouseEventListener::mouseMoveEvent(QGraphicsSceneMouseEvent *me) +{ + QDeclarativeMouseEvent dme(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers()); + emit positionChanged(&dme); +} + +void MouseEventListener::mouseReleaseEvent(QGraphicsSceneMouseEvent *me) +{ + QDeclarativeMouseEvent dme(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers()); + m_pressed = false; + emit released(&dme); +} + +void MouseEventListener::handlePressAndHold() +{ + if (m_pressed) { + //QDeclarativeMouseEvent dme = m_pressAndHoldEvent; + //const QPointF myPos = m_pressAndHoldEvent->pos(); + //QDeclarativeMouseEvent dme(myPos.x(), myPos.y(), m_pressAndHoldEvent->screenPos().x(), m_pressAndHoldEvent->screenPos().y(), m_pressAndHoldEvent->button(), m_pressAndHoldEvent->buttons(), m_pressAndHoldEvent->modifiers()); + emit pressAndHold(m_pressAndHoldEvent); + //delete m_pressAndHoldEvent; + } +} + + +bool MouseEventListener::sceneEventFilter(QGraphicsItem *item, QEvent *event) +{ + if (!isEnabled()) { + return false; + } + + switch (event->type()) { + case QEvent::GraphicsSceneMousePress: { + QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(event); + //the parent will receive events in its own coordinates + const QPointF myPos = item->mapToItem(this, me->pos()); + QDeclarativeMouseEvent dme(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers()); + m_pressAndHoldEvent = new QDeclarativeMouseEvent(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers()); + //kDebug() << "pressed in sceneEventFilter"; + emit pressed(&dme); + m_pressed = true; + //delete m_pressAndHoldEvent; + //m_pressAndHoldEvent = new QDeclarativeMouseEvent(me->pos().x(), me->pos().y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers());; + //m_pressAndHoldEvent = &dme; + QTimer::singleShot(800, this, SLOT(handlePressAndHold())); + break; + } + case QEvent::GraphicsSceneMouseMove: { + QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(event); + const QPointF myPos = item->mapToItem(this, me->pos()); + QDeclarativeMouseEvent dme(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers()); + //kDebug() << "positionChanged..." << dme.x() << dme.y(); + m_pressAndHoldEvent = new QDeclarativeMouseEvent(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers()); + emit positionChanged(&dme); + break; + } + case QEvent::GraphicsSceneMouseRelease: { + QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(event); + const QPointF myPos = item->mapToItem(this, me->pos()); + QDeclarativeMouseEvent dme(myPos.x(), myPos.y(), me->screenPos().x(), me->screenPos().y(), me->button(), me->buttons(), me->modifiers()); + emit released(&dme); + m_pressed = false; + break; + } + default: + break; + } + + return QDeclarativeItem::sceneEventFilter(item, event); +} + +#include "mouseeventlistener.moc" + diff --git a/plasma/declarativeimports/qtextracomponents/mouseeventlistener.h b/plasma/declarativeimports/qtextracomponents/mouseeventlistener.h new file mode 100644 index 0000000..ef7ecf1 --- /dev/null +++ b/plasma/declarativeimports/qtextracomponents/mouseeventlistener.h @@ -0,0 +1,100 @@ +/* + Copyright 2011 Marco Martin <notm...@gmail.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MOUSEEVENTLISTENER_H +#define MOUSEEVENTLISTENER_H + +#include <QDeclarativeItem> + +class QDeclarativeMouseEvent : public QObject +{ + Q_OBJECT + Q_PROPERTY(int x READ x) + Q_PROPERTY(int y READ y) + Q_PROPERTY(int screenX READ screenX) + Q_PROPERTY(int screenY READ screenY) + Q_PROPERTY(int button READ button) + Q_PROPERTY(int buttons READ buttons) + Q_PROPERTY(int modifiers READ modifiers) + +public: + QDeclarativeMouseEvent(int x, int y, int screenX, int screenY, + Qt::MouseButton button, + Qt::MouseButtons buttons, + Qt::KeyboardModifiers modifiers) + : m_x(x), + m_y(y), + m_screenX(screenX), + m_screenY(screenY), + m_button(button), + m_buttons(buttons), + m_modifiers(modifiers) + {} + + int x() const { return m_x; } + int y() const { return m_y; } + int screenX() const { return m_screenX; } + int screenY() const { return m_screenY; } + int button() const { return m_button; } + int buttons() const { return m_buttons; } + int modifiers() const { return m_modifiers; } + + // only for internal usage + void setX(int x) { m_x = x; } + void setY(int y) { m_y = y; } + +private: + int m_x; + int m_y; + int m_screenX; + int m_screenY; + Qt::MouseButton m_button; + Qt::MouseButtons m_buttons; + Qt::KeyboardModifiers m_modifiers; +}; + +class MouseEventListener : public QDeclarativeItem +{ + Q_OBJECT + +public: + MouseEventListener(QDeclarativeItem *parent=0); + ~MouseEventListener(); + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + bool sceneEventFilter(QGraphicsItem *i, QEvent *e); + +Q_SIGNALS: + void pressed(QDeclarativeMouseEvent *mouse); + void positionChanged(QDeclarativeMouseEvent *mouse); + void released(QDeclarativeMouseEvent *mouse); + void pressAndHold(QDeclarativeMouseEvent *mouse); + +private Q_SLOTS: + void handlePressAndHold(); +private: + bool m_pressed; + QDeclarativeMouseEvent* m_pressAndHoldEvent; + QPointF m_pressAndHoldPosition; +}; + +#endif diff --git a/plasma/declarativeimports/qtextracomponents/qtextracomponentsplugin.cpp b/plasma/declarativeimports/qtextracomponents/qtextracomponentsplugin.cpp index c094349..429282e 100644 --- a/plasma/declarativeimports/qtextracomponents/qtextracomponentsplugin.cpp +++ b/plasma/declarativeimports/qtextracomponents/qtextracomponentsplugin.cpp @@ -26,6 +26,7 @@ #include "qpixmapitem.h" #include "qimageitem.h" #include "qiconitem.h" +#include "mouseeventlistener.h" void QtExtraComponentsPlugin::registerTypes(const char *uri) @@ -35,6 +36,7 @@ void QtExtraComponentsPlugin::registerTypes(const char *uri) qmlRegisterType<QPixmapItem>(uri, 0, 1, "QPixmapItem"); qmlRegisterType<QImageItem>(uri, 0, 1, "QImageItem"); qmlRegisterType<QIconItem>(uri, 0, 1, "QIconItem"); + qmlRegisterType<MouseEventListener>(uri, 0, 1, "MouseEventListener"); } diff --git a/plasma/declarativeimports/test/gallery/Gallery.qml b/plasma/declarativeimports/test/gallery/Gallery.qml index 515b3db..b4f9f80 100644 --- a/plasma/declarativeimports/test/gallery/Gallery.qml +++ b/plasma/declarativeimports/test/gallery/Gallery.qml @@ -70,6 +70,10 @@ Rectangle { title: "Text elements" } ListElement { + page: "TextEditing.qml" + title: "Text Editing" + } + ListElement { page: "Misc.qml" title: "Misc stuff" } @@ -103,7 +107,7 @@ Rectangle { toolBar: toolBar width: page.width height: currentPage.implicitHeight - initialPage: Qt.createComponent("Buttons.qml") + initialPage: Qt.createComponent("TextEditing.qml") } } diff --git a/plasma/declarativeimports/test/gallery/Misc.qml b/plasma/declarativeimports/test/gallery/Misc.qml index aebdd73..739a0e4 100644 --- a/plasma/declarativeimports/test/gallery/Misc.qml +++ b/plasma/declarativeimports/test/gallery/Misc.qml @@ -181,7 +181,7 @@ Column { Timer { running: true repeat: true - interval: 25 + interval: 100 onTriggered: parent.value = (parent.value + 1) % 1.1 } } diff --git a/plasma/declarativeimports/test/gallery/TextEditing.qml b/plasma/declarativeimports/test/gallery/TextEditing.qml new file mode 100644 index 0000000..edc7f15 --- /dev/null +++ b/plasma/declarativeimports/test/gallery/TextEditing.qml @@ -0,0 +1,69 @@ +/* +* Copyright (C) 2011 by Daker Fernandes Pinheiro <dake...@gmail.com> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Library General Public License as +* published by the Free Software Foundation; either version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details +* +* You should have received a copy of the GNU Library General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import QtQuick 1.1 +import org.kde.plasma.components 0.1 as PlasmaComponents + +PlasmaComponents.Page { + height: editThing.height + property int implicitHeight: childrenRect.height + //scale: 1.25 + + tools: PlasmaComponents.ToolBarLayout { + spacing: 5 + PlasmaComponents.Label { + text: "Text label:" + } + PlasmaComponents.ToolButton { + text: "ToolButton" + } + PlasmaComponents.TextField { + placeholderText: "Place holder text" + } + PlasmaComponents.TextField { + text: "Text fields page" + } + } + MouseArea { + anchors.fill: editThing + onClicked: editThing.forceActiveFocus(); + } + + Column { + id: editThing + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + width: 300 + height: 300 + + spacing: 12 + Item { height: 4; width: parent.width; } + PlasmaComponents.TextField { + placeholderText: "Try copy & paste" + text: "The cat bites into the socks" + width: parent.width + clearButtonShown: true + } + PlasmaComponents.TextArea { + width: parent.width + height: 200 + placeholderText: "Touch copy & paste not implemented yet." + } + } +} diff --git a/plasma/declarativeimports/test/gallery/Texts.qml b/plasma/declarativeimports/test/gallery/Texts.qml index 53c3993..ed4d219 100644 --- a/plasma/declarativeimports/test/gallery/Texts.qml +++ b/plasma/declarativeimports/test/gallery/Texts.qml @@ -59,6 +59,7 @@ PlasmaComponents.Page { PlasmaComponents.TextField { id: tf1 placeholderText: "login" + clearButtonShown: true Keys.onTabPressed: tf2.forceActiveFocus(); } } @@ -70,6 +71,7 @@ PlasmaComponents.Page { } PlasmaComponents.TextField { id: tf2 + clearButtonShown: true width: 120 echoMode: TextInput.Password Keys.onTabPressed: loginButton.forceActiveFocus(); @@ -79,6 +81,7 @@ PlasmaComponents.Page { PlasmaComponents.Button { id: loginButton text: "Login" + z: -1 anchors { right: parent.right rightMargin: 0 @@ -90,6 +93,7 @@ PlasmaComponents.Page { PlasmaComponents.TextField { width: 120 + clearButtonShown: true placeholderText: "Disabled Text Field" Keys.onTabPressed: loginButton.forceActiveFocus(); enabled: false
_______________________________________________ Plasma-devel mailing list Plasma-devel@kde.org https://mail.kde.org/mailman/listinfo/plasma-devel