Reputation: 117
I have following code with GridView. Rectangles inside are draggable. When I drag and drop some rectangle within GridView, dragged rectangle replaces the one from drop zone, but also all other rectangles between (which have indexes between dragged and dropped) reordering their position. Is it possible to make that dragged item exchanges position only with item placed on dropped zone?
import QtQml.Models 2.2
import QtQuick 2.3
import QtQuick.Window 2.2
Window {
visible: true
width: 360
height: 360
signal changePosition
GridView {
id: root
width: 320
height: 480
cellWidth: 80
cellHeight: 80
property int lastChangedIndex: -1
property int xAxis: 0
property int yAxis: 0
displaced: Transition {
NumberAnimation {
properties: "x,y"
easing.type: Easing.OutQuad
}
}
model: DelegateModel {
id: visualModel
model: ListModel {
id: colorModel
ListElement {
color: "blue"
itemNumber: "0"
}
ListElement {
color: "green"
itemNumber: "1"
}
ListElement {
color: "red"
itemNumber: "2"
}
ListElement {
color: "yellow"
itemNumber: "3"
}
ListElement {
color: "orange"
itemNumber: "4"
}
ListElement {
color: "purple"
itemNumber: "5"
}
ListElement {
color: "cyan"
itemNumber: "6"
}
ListElement {
color: "magenta"
itemNumber: "7"
}
}
delegate: MouseArea {
id: delegateRoot
property bool held: false
property int visualIndex: DelegateModel.itemsIndex
width: 80
height: 80
drag.target: held ? icon : undefined
onPressAndHold: {
held = true
icon.opacity = 0.5
}
onReleased: {
if (held === true) {
held = false
icon.opacity = 1
icon.Drag.drop()
} else {
//action on release
}
}
Rectangle {
id: icon
width: 50
height: 50
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
color: model.color
radius: 3
Text {
anchors.centerIn: parent
text: model.itemNumber
}
Drag.active: delegateRoot.drag.active
Drag.source: delegateRoot
Drag.hotSpot.x: 36
Drag.hotSpot.y: 36
states: [
State {
when: icon.Drag.active
ParentChange {
target: icon
parent: root
}
AnchorChanges {
target: icon
anchors.horizontalCenter: undefined
anchors.verticalCenter: undefined
}
}
]
}
DropArea {
id: dropArea
anchors {
fill: parent
margins: 15
}
signal trigger
Timer {
id: dropZoneTimer
interval: 1000
onTriggered: {
dropArea.trigger()
}
}
onTrigger: {
visualModel.items.move(drag.source.visualIndex,
delegateRoot.visualIndex)
root.lastChangedIndex = delegateRoot.visualIndex
}
onEntered: {
if (drag.source.visualIndex !== delegateRoot.visualIndex) {
dropZoneTimer.start()
}
}
onExited: {
dropZoneTimer.stop()
root.lastChangedIndex = -1
}
onDropped: {
if (root.lastChangedIndex !== delegateRoot.visualIndex) {
visualModel.items.move(drag.source.visualIndex,
delegateRoot.visualIndex)
}
}
}
}
}
}
}
Upvotes: 0
Views: 2242
Reputation: 24386
The way that I'd probably do this is to swap the values of the model items, rather than actually move them:
import QtQml.Models 2.2
import QtQuick 2.3
import QtQuick.Window 2.2
Window {
visible: true
width: 360
height: 360
GridView {
id: root
width: 320
height: 480
cellWidth: 80
cellHeight: 80
displaced: Transition {
NumberAnimation {
properties: "x,y"
easing.type: Easing.OutQuad
}
}
model: DelegateModel {
id: visualModel
model: ListModel {
id: colorModel
ListElement {
color: "blue"
itemNumber: "0"
}
ListElement {
color: "green"
itemNumber: "1"
}
ListElement {
color: "red"
itemNumber: "2"
}
ListElement {
color: "yellow"
itemNumber: "3"
}
ListElement {
color: "orange"
itemNumber: "4"
}
ListElement {
color: "purple"
itemNumber: "5"
}
ListElement {
color: "cyan"
itemNumber: "6"
}
ListElement {
color: "magenta"
itemNumber: "7"
}
}
delegate: MouseArea {
id: delegateRoot
property bool held: false
property int visualIndex: DelegateModel.itemsIndex
width: 80
height: 80
drag.target: held ? icon : undefined
onPressAndHold: {
held = true
icon.opacity = 0.5
}
onReleased: {
if (held === true) {
held = false
icon.opacity = 1
icon.Drag.drop()
} else {
//action on release
}
}
Rectangle {
id: icon
width: 50
height: 50
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
color: model.color
radius: 3
Text {
anchors.centerIn: parent
text: model.itemNumber
}
Drag.active: delegateRoot.drag.active
Drag.source: delegateRoot
Drag.hotSpot.x: 36
Drag.hotSpot.y: 36
states: [
State {
when: icon.Drag.active
ParentChange {
target: icon
parent: root
}
AnchorChanges {
target: icon
anchors.horizontalCenter: undefined
anchors.verticalCenter: undefined
}
}
]
}
DropArea {
id: dropArea
anchors {
fill: parent
margins: 15
}
onDropped: {
var sourceColor = colorModel.get(drag.source.visualIndex).color;
var sourceNumber = colorModel.get(drag.source.visualIndex).itemNumber;
var targetColor = colorModel.get(delegateRoot.visualIndex).color;
var targetNumber = colorModel.get(delegateRoot.visualIndex).itemNumber;
colorModel.setProperty(drag.source.visualIndex, "color", targetColor);
colorModel.setProperty(drag.source.visualIndex, "itemNumber", targetNumber);
colorModel.setProperty(delegateRoot.visualIndex, "color", sourceColor);
colorModel.setProperty(delegateRoot.visualIndex, "itemNumber", sourceNumber);
}
}
}
}
}
}
This assumes that the usage of the itemsIndex
property (via visualIndex
) is correct.
Upvotes: 3