I'm writing a QML program that is essentially a 4x4 GridView filled with numbered rectangles. I would like to be able to:
Swap two elements from the grid, dragging and dropping
Allow swap only for directly adjacent elements
My current problem is that as soon as I drag an element on top of another, the whole grid adjusts positions filling the gap where the element originally was. Is there any way to avoid the auto adjust behavior for that type of grid?
I'm aware that the piece of code below might be the one responsible for this behavior, I just can't figure out how to change it the propper way.
DropArea {
anchors { fill: parent; margins: 15 }
onEntered: {visualModel.items.move(drag.source.visualIndex, delegateRoot.visualIndex)}
}
Full code:
import QtQuick 2.0
import QtQml.Models 2.1
GridView {
id: root
width: 320; height: 480
cellWidth: 80; cellHeight: 80
displaced: Transition {
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }//Animação anima a transicao dos tiles
}
model: DelegateModel {
id: visualModel
model: ListModel {
id: colorModel
ListElement { color: "lightsteelblue" ; text: "1" }
ListElement { color: "lightsteelblue" ; text: "2" }
ListElement { color: "lightsteelblue" ; text: "3" }
ListElement { color: "lightsteelblue" ; text: "4" }
ListElement { color: "lightsteelblue" ; text: "5" }
ListElement { color: "lightsteelblue" ; text: "6" }
ListElement { color: "lightsteelblue" ; text: "7" }
ListElement { color: "lightsteelblue" ; text: "8" }
ListElement { color: "lightsteelblue" ; text: "9" }
ListElement { color: "lightsteelblue" ; text: "10" }
ListElement { color: "lightsteelblue" ; text: "11" }
ListElement { color: "lightsteelblue" ; text: "12" }
ListElement { color: "lightsteelblue" ; text: "13" }
ListElement { color: "lightsteelblue" ; text: "14" }
ListElement { color: "lightsteelblue" ; text: "15" }
ListElement { color: "transparent" }
}
delegate: MouseArea {
id: delegateRoot
property int visualIndex: DelegateModel.itemsIndex
width: 80; height: 80
drag.target: icon
Rectangle {
id: icon
Text {
text: model.text
font.pointSize: 30
anchors.centerIn: parent
}
width: 72; height: 72
anchors {
horizontalCenter: parent.horizontalCenter;
verticalCenter: parent.verticalCenter
}
color: model.color
radius: 3
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 {
anchors { fill: parent; margins: 15 }
onEntered: {visualModel.items.move(drag.source.visualIndex, delegateRoot.visualIndex)}
}
}
}
}
I tried something but still few bugs here and there. Hope it helps.
Here is an implementation of
DropArea
that specialises for swapping adjacent elements in a 4x4 grid. See below for an explanation.The actual thought process got rather mathy. But here it is.
How do you check adjacency?
You could probably do a google search and easily find something. But I'll explain the conditions one by one.
How does one derive the Crucial Moves?
I started off by drawing on paper what would happen for a 2x2 grid. For horizontally adjacent elements, there's no problem in the swapping. The only problem occurs in swapping vertically adjacent elements.
What if my grid has a variable width and height?
Just kidding, all you need to do is to change the condition checking.
And this should be able to work with any integer width and height.
Notes
The animation for a vertical swap is not as smooth or transitional as a horizontal swap.
Tedious answer.