Warning, /frameworks/kirigami/src/controls/ListItemDragHandle.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 * SPDX-FileCopyrightText: 2018 by Marco Martin <mart@kde.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 import QtQuick 2.6 0008 import org.kde.kirigami 2.4 as Kirigami 0009 0010 /** 0011 * Implements a drag handle supposed to be in items in ListViews to reorder items. 0012 * 0013 * The QtQuick.ListView must use a model that supports item reordering, such as 0014 * QtQml.Models.ListModel.move or QAbstractItemModel instances 0015 * with QAbstractItemModel::moveRows correctly implemented. 0016 * In order for ListItemDragHandle to work correctly, the list item that is being dragged 0017 * should not directly be the delegate of the ListView, but a child of it. 0018 * 0019 * Example usage: 0020 * @include listitemdraghandle.qml 0021 * 0022 * As seen from the example, we wrapped the AbstractListItem with an 0023 * Item component. This is because when dragging the list item around, only the item that 0024 * the drag handle is assigned to is moved, and the wrapper Item stays there for 0025 * it to take up space so that other list items don't take it. 0026 * 0027 * @since org.kde.kirigami 2.5 0028 * @inherit QtQuick.Item 0029 */ 0030 Item { 0031 id: root 0032 0033 /** 0034 * @brief This property holds the delegate that will be dragged around. 0035 * 0036 * This item *must* be a child of the actual ListView's delegate. 0037 */ 0038 property Item listItem 0039 0040 /** 0041 * @brief This property holds the ListView that the delegate belong to. 0042 */ 0043 property ListView listView 0044 0045 /** 0046 * @brief This signal is emitted when the drag handle wants to move the item in the model. 0047 * 0048 * The following example does the move in the case a ListModel is used: 0049 * @code{.qml} 0050 * onMoveRequested: listModel.move(oldIndex, newIndex, 1) 0051 * @endcode 0052 * @param oldIndex the index the item is currently at 0053 * @param newIndex the index we want to move the item to 0054 */ 0055 signal moveRequested(int oldIndex, int newIndex) 0056 0057 /** 0058 * @brief This signal is emitted when the drag operation is complete and the item has been 0059 * dropped in the new final position. 0060 */ 0061 signal dropped() 0062 0063 implicitWidth: Kirigami.Units.iconSizes.smallMedium 0064 implicitHeight: implicitWidth 0065 0066 MouseArea { 0067 id: mouseArea 0068 anchors.fill: parent 0069 drag { 0070 target: listItem 0071 axis: Drag.YAxis 0072 minimumY: 0 0073 } 0074 cursorShape: pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor 0075 0076 Kirigami.Icon { 0077 id: internal 0078 source: "handle-sort" 0079 property int startY 0080 property int mouseDownY 0081 property Item originalParent 0082 opacity: mouseArea.pressed || (!Kirigami.Settings.tabletMode && listItem.hovered) ? 1 : 0.6 0083 property int listItemLastY 0084 property bool draggingUp 0085 0086 function arrangeItem() { 0087 const newIndex = listView.indexAt(1, listView.contentItem.mapFromItem(mouseArea, 0, internal.mouseDownY).y); 0088 0089 if (newIndex > -1 && ((internal.draggingUp && newIndex < index) || (!internal.draggingUp && newIndex > index))) { 0090 root.moveRequested(index, newIndex); 0091 } 0092 } 0093 0094 anchors.fill: parent 0095 } 0096 preventStealing: true 0097 0098 0099 onPressed: mouse => { 0100 internal.originalParent = listItem.parent; 0101 listItem.parent = listView; 0102 listItem.y = internal.originalParent.mapToItem(listItem.parent, listItem.x, listItem.y).y; 0103 internal.originalParent.z = 99; 0104 internal.startY = listItem.y; 0105 internal.listItemLastY = listItem.y; 0106 internal.mouseDownY = mouse.y; 0107 // while dragging listItem's height could change 0108 // we want a const maximumY during the dragging time 0109 mouseArea.drag.maximumY = listView.height - listItem.height; 0110 } 0111 0112 onPositionChanged: mouse => { 0113 if (!pressed || listItem.y === internal.listItemLastY) { 0114 return; 0115 } 0116 0117 internal.draggingUp = listItem.y < internal.listItemLastY 0118 internal.listItemLastY = listItem.y; 0119 0120 internal.arrangeItem(); 0121 0122 // autoscroll when the dragging item reaches the listView's top/bottom boundary 0123 scrollTimer.running = (listView.contentHeight > listView.height) 0124 && ( (listItem.y === 0 && !listView.atYBeginning) || 0125 (listItem.y === mouseArea.drag.maximumY && !listView.atYEnd) ); 0126 } 0127 onReleased: mouse => { 0128 listItem.y = internal.originalParent.mapFromItem(listItem, 0, 0).y; 0129 listItem.parent = internal.originalParent; 0130 dropAnimation.running = true; 0131 scrollTimer.running = false; 0132 root.dropped(); 0133 } 0134 onCanceled: released() 0135 SequentialAnimation { 0136 id: dropAnimation 0137 YAnimator { 0138 target: listItem 0139 from: listItem.y 0140 to: 0 0141 duration: Kirigami.Units.longDuration 0142 easing.type: Easing.InOutQuad 0143 } 0144 PropertyAction { 0145 target: listItem.parent 0146 property: "z" 0147 value: 0 0148 } 0149 } 0150 Timer { 0151 id: scrollTimer 0152 interval: 50 0153 repeat: true 0154 onTriggered: { 0155 if (internal.draggingUp) { 0156 listView.contentY -= Kirigami.Units.gridUnit; 0157 if (listView.atYBeginning) { 0158 listView.positionViewAtBeginning(); 0159 stop(); 0160 } 0161 } else { 0162 listView.contentY += Kirigami.Units.gridUnit; 0163 if (listView.atYEnd) { 0164 listView.positionViewAtEnd(); 0165 stop(); 0166 } 0167 } 0168 internal.arrangeItem(); 0169 } 0170 } 0171 } 0172 } 0173