aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew den Exter <andrew.den-exter@nokia.com>2011-06-09 18:29:50 +1000
committerAndrew den Exter <andrew.den-exter@nokia.com>2011-06-09 18:29:50 +1000
commit73081387d84c4b77dafeda927d1fc1ebee6cfdf2 (patch)
treece963197bc30cd034f7ddba95980ce300486bf6d
parent206a299923ca985b9ab8b47550f55a74f5473157 (diff)
Add a DragTarget element.
Provides an area that can be used to handle events when other items are dragged over it. Task-number: QMLNG-32
-rw-r--r--examples/declarative/dragtarget/dragtarget.qmlproject16
-rw-r--r--examples/declarative/dragtarget/lists/listmodel.qml256
-rw-r--r--examples/declarative/dragtarget/lists/lists.qmlproject16
-rw-r--r--examples/declarative/dragtarget/text/dragtext.qml142
-rw-r--r--examples/declarative/dragtarget/text/text.qmlproject16
-rw-r--r--examples/declarative/dragtarget/tiles/DragTile.qml59
-rw-r--r--examples/declarative/dragtarget/tiles/DropTile.qml30
-rw-r--r--examples/declarative/dragtarget/tiles/tiles.qml85
-rw-r--r--src/declarative/items/items.pri3
-rw-r--r--src/declarative/items/qsgcanvas.cpp86
-rw-r--r--src/declarative/items/qsgcanvas_p.h3
-rw-r--r--src/declarative/items/qsgdragtarget.cpp361
-rw-r--r--src/declarative/items/qsgdragtarget_p.h137
-rw-r--r--src/declarative/items/qsgevent.h137
-rw-r--r--src/declarative/items/qsgitem.cpp42
-rw-r--r--src/declarative/items/qsgitem.h5
-rw-r--r--src/declarative/items/qsgitem_p.h1
-rw-r--r--src/declarative/items/qsgitemsmodule.cpp4
-rw-r--r--src/declarative/items/qsgmousearea.cpp139
-rw-r--r--src/declarative/items/qsgmousearea_p.h32
-rw-r--r--src/declarative/items/qsgmousearea_p_p.h1
21 files changed, 1563 insertions, 8 deletions
diff --git a/examples/declarative/dragtarget/dragtarget.qmlproject b/examples/declarative/dragtarget/dragtarget.qmlproject
new file mode 100644
index 0000000000..d4909f8685
--- /dev/null
+++ b/examples/declarative/dragtarget/dragtarget.qmlproject
@@ -0,0 +1,16 @@
+import QmlProject 1.0
+
+Project {
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+ /* List of plugin directories passed to QML runtime */
+ // importPaths: [ " ../exampleplugin " ]
+}
diff --git a/examples/declarative/dragtarget/lists/listmodel.qml b/examples/declarative/dragtarget/lists/listmodel.qml
new file mode 100644
index 0000000000..50b1d397c7
--- /dev/null
+++ b/examples/declarative/dragtarget/lists/listmodel.qml
@@ -0,0 +1,256 @@
+import QtQuick 2.0
+
+
+Rectangle {
+ id: root
+ color: "grey"
+
+ width: 720
+ height: 380
+
+ Component {
+ id: draggedText
+ Text {
+ x: rootTarget.dragX - 10
+ y: rootTarget.dragY - 10
+ width: 20
+ height: 20
+
+ text: rootTarget.dragData.display
+ font.pixelSize: 18
+ }
+ }
+
+ DragTarget {
+ id: rootTarget
+
+ anchors.fill: parent
+ }
+
+ Loader {
+ anchors.fill: parent
+ sourceComponent: rootTarget.containsDrag ? draggedText : undefined
+ }
+
+ GridView {
+ id: gridView
+
+ width: 240
+ height: 360
+
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.margins: 10
+
+ cellWidth: 60
+ cellHeight: 60
+
+ model: ListModel {
+ id: gridModel
+
+ ListElement { display: "1" }
+ ListElement { display: "2" }
+ ListElement { display: "3" }
+ ListElement { display: "4" }
+ ListElement { display: "5" }
+ ListElement { display: "6" }
+ ListElement { display: "7" }
+ ListElement { display: "8" }
+ ListElement { display: "9" }
+ ListElement { display: "10" }
+ ListElement { display: "11" }
+ ListElement { display: "12" }
+ ListElement { display: "13" }
+ ListElement { display: "14" }
+ ListElement { display: "15" }
+ ListElement { display: "16" }
+ ListElement { display: "17" }
+ ListElement { display: "18" }
+ ListElement { display: "19" }
+ ListElement { display: "20" }
+ ListElement { display: "21" }
+ ListElement { display: "22" }
+ ListElement { display: "23" }
+ ListElement { display: "24" }
+ }
+
+ delegate: Rectangle {
+ id: root
+
+ width: 60
+ height: 60
+
+ color: "black"
+
+ Text {
+ anchors.fill: parent
+ color: draggable.drag.active ? "gold" : "white"
+ text: display
+ font.pixelSize: 16
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ MouseArea {
+ id: draggable
+
+ property int initialIndex
+
+ width: 60
+ height: 60
+
+ drag.data: model
+ drag.keys: ["grid"]
+ drag.target: draggable
+
+ states: State {
+ when: !draggable.drag.active
+ PropertyChanges { target: draggable; x: 0; y: 0 }
+ }
+ }
+ }
+
+ DragTarget {
+ anchors.fill: parent
+
+ keys: [ "grid" ]
+ onPositionChanged: {
+ var index = gridView.indexAt(drag.x, drag.y)
+ if (index != -1)
+ gridModel.move(drag.data.index, index, 1)
+ }
+ }
+
+ DragTarget {
+ property int dragIndex
+ anchors.fill: parent
+
+ keys: [ "list" ]
+ onEntered: {
+ dragIndex = gridView.indexAt(drag.x, drag.y)
+ if (dragIndex != -1) {
+ gridModel.insert(dragIndex, { "display": drag.data.display })
+ } else {
+ event.accepted = false
+ }
+ }
+ onPositionChanged: {
+ var index = gridView.indexAt(drag.x, drag.y);
+ if (index != -1) {
+ gridModel.move(dragIndex, index, 1)
+ dragIndex = index
+ }
+ }
+ onExited: gridModel.remove(dragIndex, 1)
+ }
+ }
+
+ ListView {
+ id: listView
+
+ width: 240
+ height: 360
+
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.margins: 10
+
+ model: ListModel {
+ id: listModel
+
+ ListElement { display: "a" }
+ ListElement { display: "b" }
+ ListElement { display: "c" }
+ ListElement { display: "d"}
+ ListElement { display: "e" }
+ ListElement { display: "f" }
+ ListElement { display: "g" }
+ ListElement { display: "h" }
+ ListElement { display: "i" }
+ ListElement { display: "j" }
+ ListElement { display: "k" }
+ ListElement { display: "l" }
+ ListElement { display: "m" }
+ ListElement { display: "n" }
+ ListElement { display: "o" }
+ ListElement { display: "p" }
+ ListElement { display: "q" }
+ ListElement { display: "r" }
+ ListElement { display: "s" }
+ ListElement { display: "t" }
+ ListElement { display: "u" }
+ ListElement { display: "v" }
+ ListElement { display: "w" }
+ ListElement { display: "x" }
+ }
+
+ delegate: Rectangle {
+ id: root
+
+ width: 240
+ height: 15
+
+ color: "black"
+
+ Text {
+ anchors.fill: parent
+ color: draggable.drag.active ? "gold" : "white"
+ text: display
+ font.pixelSize: 12
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ MouseArea {
+ id: draggable
+
+ width: 240
+ height: 15
+
+ drag.data: model
+ drag.keys: ["list"]
+ drag.target: draggable
+
+ states: State {
+ when: !draggable.drag.active
+ PropertyChanges { target: draggable; x: 0; y: 0 }
+ }
+ }
+ }
+
+ DragTarget {
+ anchors.fill: parent
+
+ keys: [ "list" ]
+ onPositionChanged: {
+ var index = listView.indexAt(drag.x, drag.y)
+ if (index != -1)
+ listModel.move(drag.data.index, index, 1)
+ }
+ }
+
+ DragTarget {
+ property int dragIndex
+ anchors.fill: parent
+
+ keys: [ "grid" ]
+
+ onEntered: {
+ dragIndex = listView.indexAt(drag.x, drag.y)
+ if (dragIndex != -1) {
+ listModel.insert(dragIndex, { "display": drag.data.display })
+ } else {
+ event.accepted = false
+ }
+ }
+ onPositionChanged: {
+ var index = listView.indexAt(drag.x, drag.y);
+ if (index != -1) {
+ listModel.move(dragIndex, index, 1)
+ dragIndex = index
+ }
+ }
+ onExited: listModel.remove(dragIndex, 1)
+ }
+ }
+}
diff --git a/examples/declarative/dragtarget/lists/lists.qmlproject b/examples/declarative/dragtarget/lists/lists.qmlproject
new file mode 100644
index 0000000000..d4909f8685
--- /dev/null
+++ b/examples/declarative/dragtarget/lists/lists.qmlproject
@@ -0,0 +1,16 @@
+import QmlProject 1.0
+
+Project {
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+ /* List of plugin directories passed to QML runtime */
+ // importPaths: [ " ../exampleplugin " ]
+}
diff --git a/examples/declarative/dragtarget/text/dragtext.qml b/examples/declarative/dragtarget/text/dragtext.qml
new file mode 100644
index 0000000000..c4a4f24f74
--- /dev/null
+++ b/examples/declarative/dragtarget/text/dragtext.qml
@@ -0,0 +1,142 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 320; height: 480
+
+ Rectangle {
+ id: inputRect
+ anchors.left: parent.left; anchors.right: parent.right; anchors.top: parent.top
+ anchors.margins: 2
+ height: input.implicitHeight + 4
+
+ border.width: 1
+
+ TextInput {
+ id: input
+ anchors.fill: parent; anchors.margins: 2
+
+ text: "the quick brown fox jumped over the lazy dog"
+
+ DragTarget {
+ id: inputTarget
+
+ anchors.fill: parent
+
+ Component {
+ id: draggedInputText
+ Text {
+ x: inputTarget.dragX
+ y: inputTarget.dragY
+ text: inputTarget.dragData
+ color: "blue"
+ font: input.font
+ }
+ }
+
+ Loader {
+ sourceComponent: parent.containsDrag ? draggedInputText : undefined
+ }
+ }
+
+
+ MouseArea {
+ id: inputDraggable
+
+ anchors.fill: parent
+ enabled: input.selectionStart != input.selectionEnd
+
+ drag.data: input.selectedText
+ drag.target: inputDraggable
+
+ drag.onDragged: {
+ var position = input.positionAt(mouse.x);
+ mouse.accepted = position >= input.selectionStart && position < input.selectionEnd
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ onPressed: {
+ var position = input.positionAt(mouse.x);
+ if (position < input.selectionStart || position >= input.selectionEnd) {
+ input.cursorPosition = position
+ } else {
+ mouse.accepted = false
+ }
+ }
+ onPositionChanged: input.moveCursorSelection(input.positionAt(mouse.x))
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ id: editRect
+ anchors.left: parent.left; anchors.right: parent.right;
+ anchors.top: inputRect.bottom; anchors.bottom: parent.bottom
+ anchors.margins: 2
+
+ border.width: 1
+
+ TextEdit {
+ id: edit
+ anchors.fill: parent; anchors.margins: 2
+
+ text: "the quick brown fox jumped over the lazy dog"
+ font.pixelSize: 18
+ wrapMode: TextEdit.WordWrap
+
+ DragTarget {
+ id: editTarget
+
+ anchors.fill: parent
+
+
+ Component {
+ id: draggedEditText
+ Text {
+ x: editTarget.dragX
+ y: editTarget.dragY
+ text: editTarget.dragData
+ color: "red"
+ font: edit.font
+ }
+ }
+
+ Loader {
+ sourceComponent: parent.containsDrag ? draggedEditText : undefined
+ }
+ }
+
+ MouseArea {
+ id: editDraggable
+
+ anchors.fill: parent
+ enabled: edit.selectionStart != edit.selectionEnd
+
+ drag.data: edit.selectedText
+ drag.target: editDraggable
+
+ drag.onDragged: {
+ var position = edit.positionAt(mouse.x, mouse.y);
+ mouse.accepted = position >= edit.selectionStart && position < edit.selectionEnd
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ onPressed: {
+ var position = edit.positionAt(mouse.x, mouse.y);
+ if (position < edit.selectionStart || position >= edit.selectionEnd) {
+ edit.cursorPosition = position
+ } else {
+ mouse.accepted = false
+ }
+ }
+ onPositionChanged: edit.moveCursorSelection(edit.positionAt(mouse.x, mouse.y))
+ }
+ }
+ }
+ }
+}
diff --git a/examples/declarative/dragtarget/text/text.qmlproject b/examples/declarative/dragtarget/text/text.qmlproject
new file mode 100644
index 0000000000..d4909f8685
--- /dev/null
+++ b/examples/declarative/dragtarget/text/text.qmlproject
@@ -0,0 +1,16 @@
+import QmlProject 1.0
+
+Project {
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+ /* List of plugin directories passed to QML runtime */
+ // importPaths: [ " ../exampleplugin " ]
+}
diff --git a/examples/declarative/dragtarget/tiles/DragTile.qml b/examples/declarative/dragtarget/tiles/DragTile.qml
new file mode 100644
index 0000000000..213373a392
--- /dev/null
+++ b/examples/declarative/dragtarget/tiles/DragTile.qml
@@ -0,0 +1,59 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: dragRectangle
+
+ property Item dropTarget
+
+ property string colorKey
+
+ color: colorKey
+
+ width: 100; height: 100
+
+ Text {
+ anchors.fill: parent
+ color: "white"
+ font.pixelSize: 90
+ text: modelData + 1
+ horizontalAlignment:Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ MouseArea {
+ id: draggable
+
+ anchors.fill: parent
+
+ drag.target: parent
+ drag.keys: [ colorKey ]
+
+ drag.onDropped: dropTarget = dropItem
+
+ states: [
+ State {
+ when: dragRectangle.dropTarget != undefined && !draggable.drag.active
+ ParentChange {
+ target: dragRectangle
+ parent: dropTarget
+ x: 0
+ y: 0
+ }
+ },
+ State {
+ when: dragRectangle.dropTarget != undefined && draggable.drag.active
+ ParentChange {
+ target: dragRectangle
+ parent: dropTarget
+ }
+ },
+ State {
+ when: !draggable.drag.active
+ AnchorChanges {
+ target: dragRectangle
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ }
+ ]
+ }
+}
diff --git a/examples/declarative/dragtarget/tiles/DropTile.qml b/examples/declarative/dragtarget/tiles/DropTile.qml
new file mode 100644
index 0000000000..9d968753db
--- /dev/null
+++ b/examples/declarative/dragtarget/tiles/DropTile.qml
@@ -0,0 +1,30 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: dropRectangle
+
+ property string colorKey
+
+ color: colorKey
+
+ width: 100; height: 100
+
+ DragTarget {
+ id: dragTarget
+
+ anchors.fill: parent
+
+ keys: [ colorKey ]
+ dropItem: dropRectangle
+ }
+
+ states: [
+ State {
+ when: dragTarget.containsDrag
+ PropertyChanges {
+ target: dropRectangle
+ color: "grey"
+ }
+ }
+ ]
+}
diff --git a/examples/declarative/dragtarget/tiles/tiles.qml b/examples/declarative/dragtarget/tiles/tiles.qml
new file mode 100644
index 0000000000..d8bcb39bd2
--- /dev/null
+++ b/examples/declarative/dragtarget/tiles/tiles.qml
@@ -0,0 +1,85 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+
+ width: 620
+ height: 410
+
+ color: "black"
+
+ DragTarget {
+ id: resetTarget
+
+ anchors.fill: parent
+ }
+
+ Grid {
+ id: redDestination
+
+ anchors.left: redSource.right; anchors.top: parent.top;
+ anchors.margins: 5
+ width: 300
+ height: 300
+
+ opacity: 0.5
+
+ columns: 3
+
+ Repeater {
+ model: 9
+ delegate: DropTile {
+ colorKey: "red"
+ }
+ }
+ }
+
+ Grid {
+ id: blueDestination
+
+ anchors.right: blueSource.left; anchors.bottom: parent.bottom;
+ anchors.margins: 5
+ width: 300
+ height: 300
+
+ opacity: 0.5
+
+ columns: 3
+
+ Repeater {
+ model: 9
+ delegate: DropTile {
+ colorKey: "blue"
+ }
+ }
+ }
+
+ Column {
+ id: redSource
+
+ anchors.left: parent.left; anchors.top: parent.top; anchors.bottom: parent.bottom
+ anchors.margins: 5
+ width: 100
+
+ Repeater {
+ model: 9
+ delegate: DragTile {
+ colorKey: "red"
+ }
+ }
+ }
+ Column {
+ id: blueSource
+
+ anchors.right: parent.right; anchors.top: parent.top; anchors.bottom: parent.bottom
+ anchors.margins: 5
+ width: 100
+
+ Repeater {
+ model: 9
+ delegate: DragTile {
+ colorKey: "blue"
+ }
+ }
+ }
+}
diff --git a/src/declarative/items/items.pri b/src/declarative/items/items.pri
index f29a82e77e..bf92025b75 100644
--- a/src/declarative/items/items.pri
+++ b/src/declarative/items/items.pri
@@ -64,6 +64,8 @@ HEADERS += \
$$PWD/qsgspriteengine_p.h \
$$PWD/qsgsprite_p.h \
$$PWD/qsgspriteimage_p.h \
+ $$PWD/qsgevent.h \
+ $$PWD/qsgdragtarget_p.h \
SOURCES += \
$$PWD/qsgevents.cpp \
@@ -106,6 +108,7 @@ SOURCES += \
$$PWD/qsgspriteengine.cpp \
$$PWD/qsgsprite.cpp \
$$PWD/qsgspriteimage.cpp \
+ $$PWD/qsgdragtarget.cpp \
SOURCES += \
$$PWD/qsgshadereffectitem.cpp \
diff --git a/src/declarative/items/qsgcanvas.cpp b/src/declarative/items/qsgcanvas.cpp
index f991609dfe..3a88fbb790 100644
--- a/src/declarative/items/qsgcanvas.cpp
+++ b/src/declarative/items/qsgcanvas.cpp
@@ -45,6 +45,8 @@
#include "qsgitem.h"
#include "qsgitem_p.h"
+#include "qsgevent.h"
+
#include <private/qsgrenderer_p.h>
#include <private/qsgflashnode_p.h>
@@ -987,6 +989,12 @@ bool QSGCanvas::event(QEvent *e)
d->clearHover();
d->lastMousePosition = QPoint();
break;
+ case QSGEvent::SGDragEnter:
+ case QSGEvent::SGDragExit:
+ case QSGEvent::SGDragMove:
+ case QSGEvent::SGDragDrop:
+ d->deliverDragEvent(static_cast<QSGDragEvent *>(e));
+ break;
default:
break;
}
@@ -1446,6 +1454,78 @@ bool QSGCanvasPrivate::deliverTouchPoints(QSGItem *item, QTouchEvent *event, con
return false;
}
+void QSGCanvasPrivate::deliverDragEvent(QSGDragEvent *event)
+{
+ Q_Q(QSGCanvas);
+ if (event->type() == QSGEvent::SGDragExit || event->type() == QSGEvent::SGDragDrop) {
+ if (QSGItem *grabItem = event->grabItem()) {
+ event->setPosition(grabItem->mapFromScene(event->scenePosition()));
+ q->sendEvent(grabItem, event);
+ }
+ } else if (!deliverDragEvent(rootItem, event)) {
+ if (QSGItem *grabItem = event->grabItem()) {
+ QSGDragEvent exitEvent(QSGEvent::SGDragExit, *event);
+ exitEvent.setPosition(grabItem->mapFromScene(event->scenePosition()));
+ q->sendEvent(grabItem, &exitEvent);
+ event->setDropItem(0);
+ event->setGrabItem(0);
+ }
+ event->setAccepted(false);
+ }
+}
+
+bool QSGCanvasPrivate::deliverDragEvent(QSGItem *item, QSGDragEvent *event)
+{
+ Q_Q(QSGCanvas);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ if (itemPrivate->opacity == 0.0)
+ return false;
+
+ if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
+ QPointF p = item->mapFromScene(event->scenePosition());
+ if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ return false;
+ }
+
+ QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QSGItem *child = children.at(ii);
+ if (!child->isVisible() || !child->isEnabled())
+ continue;
+ if (deliverDragEvent(child, event))
+ return true;
+ }
+
+ QPointF p = item->mapFromScene(event->scenePosition());
+ if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ event->setPosition(p);
+
+ if (event->type() == QSGEvent::SGDragMove && item != event->grabItem()) {
+ QSGDragEvent enterEvent(QSGEvent::SGDragEnter, *event);
+ q->sendEvent(item, &enterEvent);
+ if (enterEvent.isAccepted()) {
+ if (QSGItem *grabItem = event->grabItem()) {
+ QSGDragEvent exitEvent(QSGEvent::SGDragExit, *event);
+ q->sendEvent(grabItem, &exitEvent);
+ }
+ event->setDropItem(enterEvent.dropItem());
+ event->setGrabItem(item);
+ } else {
+ return false;
+ }
+ }
+
+ q->sendEvent(item, event);
+ if (event->isAccepted()) {
+ event->setGrabItem(item);
+ return true;
+ }
+ event->setAccepted(true);
+ }
+
+ return false;
+}
+
bool QSGCanvasPrivate::sendFilteredMouseEvent(QSGItem *target, QSGItem *item, QGraphicsSceneMouseEvent *event)
{
if (!target)
@@ -1521,6 +1601,12 @@ bool QSGCanvas::sendEvent(QSGItem *item, QEvent *e)
case QEvent::TouchEnd:
QSGItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
break;
+ case QSGEvent::SGDragEnter:
+ case QSGEvent::SGDragExit:
+ case QSGEvent::SGDragMove:
+ case QSGEvent::SGDragDrop:
+ QSGItemPrivate::get(item)->deliverDragEvent(static_cast<QSGDragEvent *>(e));
+ break;
default:
break;
}
diff --git a/src/declarative/items/qsgcanvas_p.h b/src/declarative/items/qsgcanvas_p.h
index 90132f8c91..9b2683cc38 100644
--- a/src/declarative/items/qsgcanvas_p.h
+++ b/src/declarative/items/qsgcanvas_p.h
@@ -55,6 +55,7 @@
#include "qsgitem.h"
#include "qsgcanvas.h"
+#include "qsgevent.h"
#include <private/qdeclarativeguard_p.h>
#include <private/qsgcontext_p.h>
@@ -116,6 +117,8 @@ public:
bool deliverHoverEvent(QSGItem *, QGraphicsSceneHoverEvent *);
void sendHoverEvent(QEvent::Type, QSGItem *, QGraphicsSceneHoverEvent *);
void clearHover();
+ void deliverDragEvent(QSGDragEvent *);
+ bool deliverDragEvent(QSGItem *item, QSGDragEvent *);
QDeclarativeGuard<QSGItem> hoverItem;
enum FocusOption {
diff --git a/src/declarative/items/qsgdragtarget.cpp b/src/declarative/items/qsgdragtarget.cpp
new file mode 100644
index 0000000000..c1ed167ee6
--- /dev/null
+++ b/src/declarative/items/qsgdragtarget.cpp
@@ -0,0 +1,361 @@
+/****************************************************************************
+**
+** 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 QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdragtarget_p.h"
+#include "qsgitem_p.h"
+#include "qsgcanvas.h"
+
+/*!
+ \qmlclass DragEvent QSGDragEvent
+ \brief The DragEvent object provides information about a drag event.
+
+ The position of the drag event can be obtained from the \l x and \l
+ properties, the \l keys property identifies the drag keys of the event
+ source and the \l data property contains the payload of the drag event.
+*/
+
+/*!
+ \qmlproperty real DragEvent::x
+
+ This property holds the x coordinate of a drag event.
+*/
+
+/*!
+ \qmlproperty real DragEvent::y
+
+ This property holds the y coordinate of a drag event.
+*/
+
+/*!
+ \qmlproperty stringlist DragEvent::keys
+
+ This property holds a list of keys identifying the data type or source of a
+ drag event.
+*/
+
+/*!
+ \qmlproperty variant DragEvent::data
+
+ This property holds data payload of a drag event.
+*/
+
+/*!
+ \qmlproperty real DragEvent::accepted
+
+ This property holds whether the drag event was accepted by a handler.
+
+ The default value is true.
+*/
+
+class QSGDragTargetPrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGDragTarget)
+
+public:
+ QSGDragTargetPrivate();
+ ~QSGDragTargetPrivate();
+
+ bool hasMatchingKey(const QStringList &keys) const;
+
+ QStringList keys;
+ QRegExp keyRegExp;
+ QVariant dragData;
+ QPointF dragPosition;
+ QSGItem *dropItem;
+ bool containsDrag : 1;
+};
+
+QSGDragTargetPrivate::QSGDragTargetPrivate()
+ : dropItem(0)
+ , containsDrag(false)
+{
+}
+
+QSGDragTargetPrivate::~QSGDragTargetPrivate()
+{
+}
+
+/*!
+ \qmlclass DragTarget QSGDragTarget
+ \brief The DragTarget item provides drag and drop handling.
+
+ A DragTarget is an invisible item which receives events when another item
+ is dragged over it.
+
+ A MouseArea item can be used to drag items.
+
+ The \l keys property can be used to filter drag events which don't include
+ a matching key.
+
+ The \l dropItem property is communicated to the source of a drag event as
+ the recipient of a drop on the drag target.
+
+ The \l delegate property provides a means to specify a component to be
+ instantiated for each active drag over a drag target.
+*/
+
+QSGDragTarget::QSGDragTarget(QSGItem *parent)
+ : QSGItem(*new QSGDragTargetPrivate, parent)
+{
+}
+
+QSGDragTarget::~QSGDragTarget()
+{
+}
+
+/*!
+ \qmlproperty bool DragTarget::containsDrag
+
+ This property identifies whether the DragTarget currently contains any
+ dragged items.
+*/
+
+bool QSGDragTarget::containsDrag() const
+{
+ Q_D(const QSGDragTarget);
+ return d->containsDrag;
+}
+
+/*!
+ \qmlproperty stringlist DragTarget::keys
+
+ This property holds a list of drag keys a DragTarget will accept.
+*/
+
+QStringList QSGDragTarget::keys() const
+{
+ Q_D(const QSGDragTarget);
+ return d->keys;
+}
+
+void QSGDragTarget::setKeys(const QStringList &keys)
+{
+ Q_D(QSGDragTarget);
+ if (d->keys != keys) {
+ d->keys = keys;
+
+ if (keys.isEmpty()) {
+ d->keyRegExp = QRegExp();
+ } else {
+ QString pattern = QLatin1Char('(') + QRegExp::escape(keys.first());
+ for (int i = 1; i < keys.count(); ++i)
+ pattern += QLatin1Char('|') + QRegExp::escape(keys.at(i));
+ pattern += QLatin1Char(')');
+ d->keyRegExp = QRegExp(pattern.replace(QLatin1String("\\*"), QLatin1String(".+")));
+ }
+ emit keysChanged();
+ }
+}
+
+/*!
+ \qmlproperty Item DragTarget::dropItem
+
+ This property identifies an item as the recipient of a drop event within
+ a DragTarget.
+
+ \sa MouseArea::drag.dropItem
+*/
+
+QSGItem *QSGDragTarget::dropItem() const
+{
+ Q_D(const QSGDragTarget);
+ return d->dropItem;
+}
+
+void QSGDragTarget::setDropItem(QSGItem *item)
+{
+ Q_D(QSGDragTarget);
+ if (d->dropItem != item) {
+ d->dropItem = item;
+ emit dropItemChanged();
+ }
+}
+
+void QSGDragTarget::resetDropItem()
+{
+ Q_D(QSGDragTarget);
+ if (d->dropItem) {
+ d->dropItem = 0;
+ emit dropItemChanged();
+ }
+}
+
+qreal QSGDragTarget::dragX() const
+{
+ Q_D(const QSGDragTarget);
+ return d->dragPosition.x();
+}
+
+qreal QSGDragTarget::dragY() const
+{
+ Q_D(const QSGDragTarget);
+ return d->dragPosition.y();
+}
+
+QVariant QSGDragTarget::dragData() const
+{
+ Q_D(const QSGDragTarget);
+ return d->dragData;
+}
+
+/*!
+ \qmlsignal DragTarget::onPositionChanged(DragEvent drag)
+ \qmlattachedsignal DragTarget::onPositionChanged(DragEvent drag)
+
+ This handler is called when the position of a drag has changed.
+*/
+
+void QSGDragTarget::dragMoveEvent(QSGDragEvent *event)
+{
+ Q_D(QSGDragTarget);
+ if (!d->containsDrag) {
+ event->setAccepted(false);
+ return;
+ }
+
+ event->setDropItem(d->dropItem);
+
+ d->dragPosition = event->position();
+ emit dragPositionChanged();
+
+ QSGDragTargetEvent dragTargetEvent(event);
+ emit positionChanged(&dragTargetEvent);
+}
+
+bool QSGDragTargetPrivate::hasMatchingKey(const QStringList &keys) const
+{
+ if (keyRegExp.isEmpty())
+ return true;
+
+ foreach (const QString &key, keys) {
+ if (keyRegExp.exactMatch(key))
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \qmlsignal DragTarget::onEntered(DragEvent drag)
+ \qmlattachedsignal DragTarget::onEntered(DragEvent drag)
+
+ This handler is called when a drag enters the bounds of a DragTarget.
+*/
+
+void QSGDragTarget::dragEnterEvent(QSGDragEvent *event)
+{
+ Q_D(QSGDragTarget);
+ if (!d->effectiveEnable || !d->hasMatchingKey(event->keys()) || d->containsDrag) {
+ event->setAccepted(false);
+ return;
+ }
+
+ event->setDropItem(d->dropItem);
+
+ QSGDragTargetEvent dragTargetEvent(event);
+ emit entered(&dragTargetEvent);
+
+ if (event->isAccepted()) {
+
+ d->dragData = event->data();
+ d->containsDrag = true;
+ if (!d->dragData.isNull())
+ emit dragDataChanged();
+ emit containsDragChanged();
+ }
+}
+
+/*!
+ \qmlsignal DragTarget::onExited(DragEvent drag)
+ \qmlattachedsignal DragTarget::onExited(DragEvent drag)
+
+ This handler is called when a drag exits the bounds of a DragTarget.
+*/
+
+void QSGDragTarget::dragExitEvent(QSGDragEvent *event)
+{
+ Q_D(QSGDragTarget);
+ if (!d->containsDrag) {
+ event->setAccepted(false);
+ return;
+ }
+
+ QSGDragTargetEvent dragTargetEvent(event);
+ emit exited(&dragTargetEvent);
+
+ d->containsDrag = false;
+ emit containsDragChanged();
+ if (!d->dragData.isNull()) {
+ d->dragData = QVariant();
+ emit dragDataChanged();
+ }
+}
+
+/*!
+ \qmlsignal DragTarget::onDropped(DragEvent drag)
+ \qmlattachedsignal DragTarget::onDropped(DragEvent drag)
+
+ This handler is called when a drop event occurs within the bounds of a
+ a DragTarget.
+*/
+
+void QSGDragTarget::dragDropEvent(QSGDragEvent *event)
+{
+ Q_D(QSGDragTarget);
+ if (!d->containsDrag) {
+ event->setAccepted(false);
+ return;
+ }
+
+ event->setDropItem(d->dropItem);
+
+ QSGDragTargetEvent dragTargetEvent(event);
+ emit dropped(&dragTargetEvent);
+
+ d->containsDrag = false;
+ emit containsDragChanged();
+ if (!d->dragData.isNull()) {
+ d->dragData = QVariant();
+ emit dragDataChanged();
+ }
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/items/qsgdragtarget_p.h b/src/declarative/items/qsgdragtarget_p.h
new file mode 100644
index 0000000000..ad13e11854
--- /dev/null
+++ b/src/declarative/items/qsgdragtarget_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** 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 QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGDRAGTARGET_P_H
+#define QSGDRAGTARGET_P_H
+
+#include "qsgitem.h"
+#include "qsgevent.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGDragTargetEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal x READ x)
+ Q_PROPERTY(qreal y READ y)
+ Q_PROPERTY(QVariant data READ data)
+ Q_PROPERTY(QStringList keys READ keys)
+ Q_PROPERTY(bool accepted READ accepted WRITE setAccepted)
+public:
+ QSGDragTargetEvent(QSGDragEvent *event) : _event(event) {}
+
+ qreal x() const { return _event->x(); }
+ qreal y() const { return _event->y(); }
+
+ QVariant data() const { return _event->data(); }
+ QStringList keys() const { return _event->keys(); }
+
+ bool accepted() const { return _event->isAccepted(); }
+ void setAccepted(bool accepted) { _event->setAccepted(accepted); }
+
+private:
+ QSGDragEvent *_event;
+};
+
+class QSGDragTargetPrivate;
+class Q_AUTOTEST_EXPORT QSGDragTarget : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool containsDrag READ containsDrag NOTIFY containsDragChanged)
+ Q_PROPERTY(QSGItem *dropItem READ dropItem WRITE setDropItem NOTIFY dropItemChanged RESET resetDropItem)
+ Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged)
+ Q_PROPERTY(qreal dragX READ dragX NOTIFY dragPositionChanged)
+ Q_PROPERTY(qreal dragY READ dragY NOTIFY dragPositionChanged)
+ Q_PROPERTY(QVariant dragData READ dragData NOTIFY dragDataChanged)
+
+public:
+ QSGDragTarget(QSGItem *parent=0);
+ ~QSGDragTarget();
+
+ bool containsDrag() const;
+ void setContainsDrag(bool drag);
+
+ QStringList keys() const;
+ void setKeys(const QStringList &keys);
+
+ QSGItem *dropItem() const;
+ void setDropItem(QSGItem *item);
+ void resetDropItem();
+
+ qreal dragX() const;
+ qreal dragY() const;
+ QVariant dragData() const;
+
+Q_SIGNALS:
+ void containsDragChanged();
+ void keysChanged();
+ void dropItemChanged();
+ void dragPositionChanged();
+ void dragDataChanged();
+
+ void entered(QSGDragTargetEvent *drag);
+ void exited(QSGDragTargetEvent *drag);
+ void positionChanged(QSGDragTargetEvent *drag);
+ void dropped(QSGDragTargetEvent *drag);
+
+protected:
+ void dragMoveEvent(QSGDragEvent *event);
+ void dragEnterEvent(QSGDragEvent *event);
+ void dragExitEvent(QSGDragEvent *event);
+ void dragDropEvent(QSGDragEvent *event);
+
+private:
+ Q_DISABLE_COPY(QSGDragTarget)
+ Q_DECLARE_PRIVATE(QSGDragTarget)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGDragTargetEvent)
+QML_DECLARE_TYPE(QSGDragTarget)
+
+QT_END_HEADER
+
+#endif // QSGDRAGTARGET_P_H
diff --git a/src/declarative/items/qsgevent.h b/src/declarative/items/qsgevent.h
new file mode 100644
index 0000000000..93b53d1312
--- /dev/null
+++ b/src/declarative/items/qsgevent.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDRAGEVENT_H
+#define QDRAGEVENT_H
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qnamespace.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItem;
+
+class Q_DECLARATIVE_EXPORT QSGEvent : public QEvent
+{
+public:
+ // XXX: Merge types into QEvent or formally reserve a suitable range.
+ // Alternatively start from QEvent::User and add a SGUser value for use by items.
+ enum SGType
+ {
+ SGDragEnter = 600,
+ SGDragExit,
+ SGDragMove,
+ SGDragDrop
+ };
+
+ QSGEvent(QSGEvent::SGType type) : QEvent(Type(type)) {}
+
+ SGType type() const { return SGType(QEvent::type()); }
+};
+
+class Q_DECLARATIVE_EXPORT QSGDragEvent : public QSGEvent
+{
+public:
+ QSGDragEvent(
+ SGType type,
+ const QPointF &scenePosition,
+ const QVariant &data,
+ const QStringList &keys,
+ QSGItem *grabItem = 0)
+ : QSGEvent(type)
+ , _scenePosition(scenePosition),
+ _data(data)
+ , _keys(keys)
+ , _dropItem(0)
+ , _grabItem(grabItem)
+ {
+ }
+ QSGDragEvent(SGType type, const QSGDragEvent &event)
+ : QSGEvent(type)
+ , _scenePosition(event._scenePosition)
+ , _position(event._position)
+ , _data(event._data)
+ , _keys(event._keys)
+ , _dropItem(event._dropItem)
+ , _grabItem(event._grabItem)
+ {
+ }
+
+ QVariant data() const { return _data; }
+
+ qreal x() const { return _position.x(); }
+ qreal y() const { return _position.y(); }
+ QPointF position() const { return _position; }
+ void setPosition(const QPointF &position) { _position = position; }
+
+ QPointF scenePosition() const { return _scenePosition; }
+
+ QStringList keys() const { return _keys; }
+
+ QSGItem *dropItem() const { return _dropItem; }
+ void setDropItem(QSGItem *dropItem) { _dropItem = dropItem; }
+
+ QSGItem *grabItem() const { return _grabItem; }
+ void setGrabItem(QSGItem *item) { _grabItem = item; }
+
+private:
+ QPointF _scenePosition;
+ QPointF _position;
+ QVariant _data;
+ QStringList _keys;
+ QSGItem *_dropItem;
+ QSGItem *_grabItem;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
+
diff --git a/src/declarative/items/qsgitem.cpp b/src/declarative/items/qsgitem.cpp
index f2d26955aa..328da16ff4 100644
--- a/src/declarative/items/qsgitem.cpp
+++ b/src/declarative/items/qsgitem.cpp
@@ -45,6 +45,7 @@
#include "qsgcanvas.h"
#include <QtScript/qscriptengine.h>
#include "qsgcanvas_p.h"
+#include "qsgevent.h"
#include "qsgevents_p_p.h"
@@ -1689,6 +1690,26 @@ void QSGItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
Q_UNUSED(event);
}
+void QSGItem::dragMoveEvent(QSGDragEvent *event)
+{
+ event->setAccepted(false);
+}
+
+void QSGItem::dragEnterEvent(QSGDragEvent *event)
+{
+ event->setAccepted(false);
+}
+
+void QSGItem::dragExitEvent(QSGDragEvent *event)
+{
+ event->setAccepted(false);
+}
+
+void QSGItem::dragDropEvent(QSGDragEvent *event)
+{
+ event->setAccepted(false);
+}
+
bool QSGItem::childMouseEventFilter(QSGItem *, QEvent *)
{
return false;
@@ -2151,6 +2172,27 @@ void QSGItemPrivate::deliverHoverEvent(QGraphicsSceneHoverEvent *e)
}
}
+void QSGItemPrivate::deliverDragEvent(QSGDragEvent *e)
+{
+ Q_Q(QSGItem);
+ switch (e->type()) {
+ default:
+ Q_ASSERT(!"Unknown event type");
+ case QSGEvent::SGDragEnter:
+ q->dragEnterEvent(e);
+ break;
+ case QSGEvent::SGDragExit:
+ q->dragExitEvent(e);
+ break;
+ case QSGEvent::SGDragMove:
+ q->dragMoveEvent(e);
+ break;
+ case QSGEvent::SGDragDrop:
+ q->dragDropEvent(e);
+ break;
+ }
+}
+
void QSGItem::itemChange(ItemChange change, const ItemChangeData &value)
{
Q_UNUSED(change);
diff --git a/src/declarative/items/qsgitem.h b/src/declarative/items/qsgitem.h
index 564d819000..995b5cbcd1 100644
--- a/src/declarative/items/qsgitem.h
+++ b/src/declarative/items/qsgitem.h
@@ -89,6 +89,7 @@ class QSGKeyEvent;
class QSGAnchors;
class QSGItemPrivate;
class QSGCanvas;
+class QSGDragEvent;
class QSGEngine;
class QTouchEvent;
class QSGNode;
@@ -363,6 +364,10 @@ protected:
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ virtual void dragMoveEvent(QSGDragEvent *event);
+ virtual void dragEnterEvent(QSGDragEvent *event);
+ virtual void dragExitEvent(QSGDragEvent *event);
+ virtual void dragDropEvent(QSGDragEvent *event);
virtual bool childMouseEventFilter(QSGItem *, QEvent *);
virtual void geometryChanged(const QRectF &newGeometry,
diff --git a/src/declarative/items/qsgitem_p.h b/src/declarative/items/qsgitem_p.h
index 0f4a3213b4..300ccdc49e 100644
--- a/src/declarative/items/qsgitem_p.h
+++ b/src/declarative/items/qsgitem_p.h
@@ -324,6 +324,7 @@ public:
void deliverWheelEvent(QGraphicsSceneWheelEvent *);
void deliverTouchEvent(QTouchEvent *);
void deliverHoverEvent(QGraphicsSceneHoverEvent *);
+ void deliverDragEvent(QSGDragEvent *);
bool calcEffectiveVisible() const;
void setEffectiveVisibleRecur(bool);
diff --git a/src/declarative/items/qsgitemsmodule.cpp b/src/declarative/items/qsgitemsmodule.cpp
index a29776fc68..f1e3a0cb91 100644
--- a/src/declarative/items/qsgitemsmodule.cpp
+++ b/src/declarative/items/qsgitemsmodule.cpp
@@ -77,6 +77,7 @@
#include "qsgcontext2d_p.h"
#include "qsgsprite_p.h"
#include "qsgspriteimage_p.h"
+#include "qsgdragtarget_p.h"
static QDeclarativePrivate::AutoParentResult qsgitem_autoParent(QObject *obj, QObject *parent)
{
@@ -189,6 +190,9 @@ static void qt_sgitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QSGAnchorSet>();
qmlRegisterType<QSGAnchorAnimation>(uri, major, minor,"AnchorAnimation");
qmlRegisterType<QSGParentAnimation>(uri, major, minor,"ParentAnimation");
+
+ qmlRegisterType<QSGDragTarget>("QtQuick", 2, 0, "DragTarget");
+ qmlRegisterType<QSGDragTargetEvent>();
}
void QSGItemsModule::defineModule()
diff --git a/src/declarative/items/qsgmousearea.cpp b/src/declarative/items/qsgmousearea.cpp
index 887d78a64d..6b4311e698 100644
--- a/src/declarative/items/qsgmousearea.cpp
+++ b/src/declarative/items/qsgmousearea.cpp
@@ -43,6 +43,7 @@
#include "qsgmousearea_p.h"
#include "qsgmousearea_p_p.h"
#include "qsgcanvas.h"
+#include "qsgevent.h"
#include "qsgevents_p_p.h"
#include <QtGui/qgraphicssceneevent.h>
@@ -54,8 +55,8 @@ QT_BEGIN_NAMESPACE
static const int PressAndHoldDelay = 800;
QSGDrag::QSGDrag(QObject *parent)
-: QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX), _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX),
-_active(false), _filterChildren(false)
+: QObject(parent), _target(0), _dropItem(0), _grabItem(0), _axis(XandYAxis), _xmin(-FLT_MAX),
+_xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false)
{
}
@@ -78,12 +79,70 @@ void QSGDrag::setTarget(QSGItem *t)
void QSGDrag::resetTarget()
{
- if (!_target)
+ if (_target == 0)
return;
_target = 0;
emit targetChanged();
}
+/*!
+ \qmlproperty Item MouseArea::drag.dropItem
+
+ This property holds the item an active drag will be dropped on if released
+ at the current position.
+*/
+
+QSGItem *QSGDrag::dropItem() const
+{
+ return _dropItem;
+}
+
+void QSGDrag::setDropItem(QSGItem *item)
+{
+ if (_dropItem != item) {
+ _dropItem = item;
+ emit dropItemChanged();
+ }
+}
+
+QSGItem *QSGDrag::grabItem() const
+{
+ return _grabItem;
+}
+
+void QSGDrag::setGrabItem(QSGItem *item)
+{
+ _grabItem = item;
+}
+
+/*!
+ \qmlproperty variant MouseArea::drag.data
+
+ This property holds the data sent to recipients of drag events generated
+ by a MouseArea.
+*/
+
+QVariant QSGDrag::data() const
+{
+ return _data;
+}
+
+void QSGDrag::setData(const QVariant &data)
+{
+ if (_data != data) {
+ _data = data;
+ emit dataChanged();
+ }
+}
+
+void QSGDrag::resetData()
+{
+ if (!_data.isNull()) {
+ _data = QVariant();
+ emit dataChanged();
+ }
+}
+
QSGDrag::Axis QSGDrag::axis() const
{
return _axis;
@@ -175,9 +234,30 @@ void QSGDrag::setFilterChildren(bool filter)
emit filterChildrenChanged();
}
+/*!
+ \qmlproperty stringlist MouseArea::drag.keys
+
+ This property holds a list of keys drag recipients can use to identify the
+ source or data type of a drag event.
+*/
+
+QStringList QSGDrag::keys() const
+{
+ return _keys;
+}
+
+void QSGDrag::setKeys(const QStringList &keys)
+{
+ if (_keys != keys) {
+ _keys = keys;
+ emit keysChanged();
+ }
+}
+
QSGMouseAreaPrivate::QSGMouseAreaPrivate()
: absorb(true), hovered(false), pressed(false), longPress(false),
- moved(false), stealMouse(false), doubleClick(false), preventStealing(false), drag(0)
+ moved(false), stealMouse(false), doubleClick(false), preventStealing(false), dragRejected(false),
+ drag(0)
{
Q_Q(QSGMouseArea);
forwardTo = QDeclarativeListProperty<QSGItem>(q, forwardToList);
@@ -384,6 +464,7 @@ void QSGMouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
QSGItem::mousePressEvent(event);
else {
d->longPress = false;
+ d->dragRejected = false;
d->saveEvent(event);
if (d->drag) {
d->dragX = drag()->axis() & QSGDrag::XAxis;
@@ -440,8 +521,24 @@ void QSGMouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
- if (keepMouseGrab() && d->stealMouse)
- d->drag->setActive(true);
+ if (keepMouseGrab() && d->stealMouse && !d->dragRejected && !d->drag->active()) {
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
+ d->drag->emitDragged(&me);
+ if (me.isAccepted()) {
+ d->drag->setActive(true);
+ QSGDragEvent dragEvent(
+ QSGEvent::SGDragEnter,
+ d->startScene,
+ d->drag->data(),
+ d->drag->keys());
+ QCoreApplication::sendEvent(canvas(), &dragEvent);
+
+ d->drag->setGrabItem(dragEvent.grabItem());
+ d->drag->setDropItem(dragEvent.dropItem());
+ } else {
+ d->dragRejected = true;
+ }
+ }
if (d->dragX && d->drag->active()) {
qreal x = (curLocalPos.x() - startLocalPos.x()) + d->startX;
@@ -470,6 +567,18 @@ void QSGMouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
}
d->moved = true;
+
+ if (d->drag->active()) {
+ QSGDragEvent dragEvent(
+ QSGEvent::SGDragMove,
+ event->scenePos(),
+ d->drag->data(),
+ d->drag->keys(),
+ d->drag->grabItem());
+ QCoreApplication::sendEvent(canvas(), &dragEvent);
+ d->drag->setGrabItem(dragEvent.grabItem());
+ d->drag->setDropItem(dragEvent.dropItem());
+ }
}
QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
emit mousePositionChanged(&me);
@@ -490,8 +599,24 @@ void QSGMouseArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
} else {
d->saveEvent(event);
setPressed(false);
- if (d->drag)
+ if (d->drag && d->drag->active()) {
+ QSGDragEvent dragEvent(
+ QSGEvent::SGDragDrop,
+ event->scenePos(),
+ d->drag->data(),
+ d->drag->keys(),
+ d->drag->grabItem());
+ QCoreApplication::sendEvent(canvas(), &dragEvent);
+ d->drag->setGrabItem(0);
+ if (dragEvent.isAccepted()) {
+ d->drag->setDropItem(dragEvent.dropItem());
+ d->drag->emitDropped(dragEvent.dropItem());
+ } else {
+ d->drag->emitCanceled();
+ }
+ d->drag->setDropItem(0);
d->drag->setActive(false);
+ }
// If we don't accept hover, we need to reset containsMouse.
if (!acceptHoverEvents())
setHovered(false);
diff --git a/src/declarative/items/qsgmousearea_p.h b/src/declarative/items/qsgmousearea_p.h
index 469b9f7168..d7248bca37 100644
--- a/src/declarative/items/qsgmousearea_p.h
+++ b/src/declarative/items/qsgmousearea_p.h
@@ -51,12 +51,15 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
+class QSGMouseEvent;
class Q_AUTOTEST_EXPORT QSGDrag : public QObject
{
Q_OBJECT
Q_ENUMS(Axis)
Q_PROPERTY(QSGItem *target READ target WRITE setTarget NOTIFY targetChanged RESET resetTarget)
+ Q_PROPERTY(QSGItem *dropItem READ dropItem NOTIFY dropItemChanged)
+ Q_PROPERTY(QVariant data READ data WRITE setData NOTIFY dataChanged RESET resetData)
Q_PROPERTY(Axis axis READ axis WRITE setAxis NOTIFY axisChanged)
Q_PROPERTY(qreal minimumX READ xmin WRITE setXmin NOTIFY minimumXChanged)
Q_PROPERTY(qreal maximumX READ xmax WRITE setXmax NOTIFY maximumXChanged)
@@ -64,6 +67,7 @@ class Q_AUTOTEST_EXPORT QSGDrag : public QObject
Q_PROPERTY(qreal maximumY READ ymax WRITE setYmax NOTIFY maximumYChanged)
Q_PROPERTY(bool active READ active NOTIFY activeChanged)
Q_PROPERTY(bool filterChildren READ filterChildren WRITE setFilterChildren NOTIFY filterChildrenChanged)
+ Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged)
//### consider drag and drop
public:
@@ -74,6 +78,16 @@ public:
void setTarget(QSGItem *);
void resetTarget();
+ QSGItem *dropItem() const;
+ void setDropItem(QSGItem *item);
+
+ QSGItem *grabItem() const;
+ void setGrabItem(QSGItem *grabItem);
+
+ QVariant data() const;
+ void setData(const QVariant &data);
+ void resetData();
+
enum Axis { XAxis=0x01, YAxis=0x02, XandYAxis=0x03 };
Axis axis() const;
void setAxis(Axis);
@@ -93,8 +107,17 @@ public:
bool filterChildren() const;
void setFilterChildren(bool);
+ QStringList keys() const;
+ void setKeys(const QStringList &keys);
+
+ void emitDragged(QSGMouseEvent *event) { emit dragged(event); }
+ void emitDropped(QSGItem *dropItem) { emit dropped(dropItem); }
+ void emitCanceled() { emit canceled(); }
+
Q_SIGNALS:
void targetChanged();
+ void dropItemChanged();
+ void dataChanged();
void axisChanged();
void minimumXChanged();
void maximumXChanged();
@@ -102,9 +125,17 @@ Q_SIGNALS:
void maximumYChanged();
void activeChanged();
void filterChildrenChanged();
+ void keysChanged();
+ void dragged(QSGMouseEvent *mouse);
+ void dropped(QSGItem *dropItem);
+ void canceled();
private:
+ QStringList _keys;
+ QVariant _data;
QSGItem *_target;
+ QSGItem *_dropItem;
+ QSGItem *_grabItem;
Axis _axis;
qreal _xmin;
qreal _xmax;
@@ -115,7 +146,6 @@ private:
Q_DISABLE_COPY(QSGDrag)
};
-class QSGMouseEvent;
class QSGMouseAreaPrivate;
class Q_AUTOTEST_EXPORT QSGMouseArea : public QSGItem
{
diff --git a/src/declarative/items/qsgmousearea_p_p.h b/src/declarative/items/qsgmousearea_p_p.h
index e736c059a2..11f7089503 100644
--- a/src/declarative/items/qsgmousearea_p_p.h
+++ b/src/declarative/items/qsgmousearea_p_p.h
@@ -96,6 +96,7 @@ public:
bool stealMouse : 1;
bool doubleClick : 1;
bool preventStealing : 1;
+ bool dragRejected : 1;
QSGDrag *drag;
QPointF startScene;
qreal startX;