148 lines
5.1 KiB
QML
148 lines
5.1 KiB
QML
import QtQuick 2.13
|
|
import QtQuick.Layouts 1.15
|
|
import org.kde.kirigami 2.13 as Kirigami
|
|
|
|
Item {
|
|
id: root
|
|
|
|
/**
|
|
* @brief This property holds the delegate that will be dragged around.
|
|
*
|
|
* This item *must* be a child of the actual ListView's delegate.
|
|
*/
|
|
property Item listItem
|
|
|
|
/**
|
|
* @brief This property holds the ListView that the delegate belong to.
|
|
*/
|
|
property ListView listView
|
|
|
|
/**
|
|
* @brief This signal is emitted when the drag handle wants to move the item in the model.
|
|
*
|
|
* The following example does the move in the case a ListModel is used:
|
|
* @code{.qml}
|
|
* onMoveRequested: listModel.move(oldIndex, newIndex, 1)
|
|
* @endcode
|
|
* @param oldIndex the index the item is currently at
|
|
* @param newIndex the index we want to move the item to
|
|
*/
|
|
signal moveRequested(int oldIndex, int newIndex)
|
|
|
|
/**
|
|
* @brief This signal is emitted when the drag operation is complete and the item has been
|
|
* dropped in the new final position.
|
|
*/
|
|
signal dropped()
|
|
|
|
implicitWidth: Kirigami.Units.iconSizes.smallMedium
|
|
implicitHeight: implicitWidth
|
|
|
|
MouseArea {
|
|
id: mouseArea
|
|
anchors.fill: parent
|
|
drag {
|
|
target: listItem
|
|
axis: Drag.YAxis
|
|
minimumY: 0
|
|
}
|
|
cursorShape: pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor
|
|
|
|
Kirigami.Icon {
|
|
id: internal
|
|
source: "handle-sort"
|
|
property int startY
|
|
property int mouseDownY
|
|
property Item originalParent
|
|
opacity: mouseArea.pressed || (!Kirigami.Settings.tabletMode && listItem.hovered) ? 1 : 0.6
|
|
property int listItemLastY
|
|
property bool draggingUp
|
|
color: "white"
|
|
|
|
function arrangeItem() {
|
|
const newIndex = listView.indexAt(1, listView.contentItem.mapFromItem(mouseArea, 0, internal.mouseDownY).y);
|
|
|
|
if (newIndex > -1 && ((internal.draggingUp && newIndex < index) || (!internal.draggingUp && newIndex > index))) {
|
|
root.moveRequested(index, newIndex);
|
|
}
|
|
}
|
|
|
|
anchors.fill: parent
|
|
}
|
|
preventStealing: true
|
|
|
|
|
|
onPressed: mouse => {
|
|
internal.originalParent = listItem.parent;
|
|
listItem.parent = listView;
|
|
listItem.y = internal.originalParent.mapToItem(listItem.parent, listItem.x, listItem.y).y;
|
|
internal.originalParent.z = 99;
|
|
internal.startY = listItem.y;
|
|
internal.listItemLastY = listItem.y;
|
|
internal.mouseDownY = mouse.y;
|
|
// while dragging listItem's height could change
|
|
// we want a const maximumY during the dragging time
|
|
mouseArea.drag.maximumY = listView.height - listItem.height;
|
|
}
|
|
|
|
onPositionChanged: mouse => {
|
|
if (!pressed || listItem.y === internal.listItemLastY) {
|
|
return;
|
|
}
|
|
|
|
internal.draggingUp = listItem.y < internal.listItemLastY
|
|
internal.listItemLastY = listItem.y;
|
|
|
|
internal.arrangeItem();
|
|
|
|
// autoscroll when the dragging item reaches the listView's top/bottom boundary
|
|
scrollTimer.running = (listView.contentHeight > listView.height)
|
|
&& ( (listItem.y === 0 && !listView.atYBeginning) ||
|
|
(listItem.y === mouseArea.drag.maximumY && !listView.atYEnd) );
|
|
}
|
|
onReleased: mouse => {
|
|
listItem.y = internal.originalParent.mapFromItem(listItem, 0, 0).y;
|
|
listItem.parent = internal.originalParent;
|
|
dropAnimation.running = true;
|
|
scrollTimer.running = false;
|
|
root.dropped();
|
|
}
|
|
onCanceled: released()
|
|
SequentialAnimation {
|
|
id: dropAnimation
|
|
YAnimator {
|
|
target: listItem
|
|
from: listItem.y
|
|
to: 0
|
|
duration: Kirigami.Units.longDuration
|
|
easing.type: Easing.InOutQuad
|
|
}
|
|
PropertyAction {
|
|
target: listItem.parent
|
|
property: "z"
|
|
value: 0
|
|
}
|
|
}
|
|
Timer {
|
|
id: scrollTimer
|
|
interval: 50
|
|
repeat: true
|
|
onTriggered: {
|
|
if (internal.draggingUp) {
|
|
listView.contentY -= Kirigami.Units.gridUnit;
|
|
if (listView.atYBeginning) {
|
|
listView.positionViewAtBeginning();
|
|
stop();
|
|
}
|
|
} else {
|
|
listView.contentY += Kirigami.Units.gridUnit;
|
|
if (listView.atYEnd) {
|
|
listView.positionViewAtEnd();
|
|
stop();
|
|
}
|
|
}
|
|
internal.arrangeItem();
|
|
}
|
|
}
|
|
}
|
|
}
|