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 0008 import org.kde.kirigami 2 as Kirigami 0009 0010 /** 0011 * Implements a drag handle supposed to be in items in ListViews to reorder items 0012 * The ListView must visualize a model which supports item reordering, 0013 * such as ListModel.move() or QAbstractItemModel instances with moveRows() correctly implemented. 0014 * In order for ListItemDragHandle to work correctly, the listItem that is being dragged 0015 * should not directly be the delegate of the ListView, but a child of it. 0016 * 0017 * It is recommended to use DelagateRecycler as base delegate like the following code: 0018 * @code 0019 * import QtQuick 2.15 0020 * import QtQuick.Layouts 1.15 0021 * import QtQuick.Controls 2.15 as QQC2 0022 * import org.kde.kirigami 2.19 as Kirigami 0023 * ... 0024 * Component { 0025 * id: delegateComponent 0026 * QQC2.ItemDelegate { 0027 * id: listItem 0028 * contentItem: RowLayout { 0029 * Kirigami.ListItemDragHandle { 0030 * listItem: listItem 0031 * listView: mainList 0032 * onMoveRequested: (oldIndex, newIndex) => { 0033 * listModel.move(oldIndex, newIndex, 1); 0034 * } 0035 * } 0036 * QQC2.Label { 0037 * text: model.label 0038 * } 0039 * } 0040 * } 0041 * } 0042 * ListView { 0043 * id: mainList 0044 * 0045 * model: ListModel { 0046 * id: listModel 0047 * ListElement { 0048 * label: "Item 1" 0049 * } 0050 * ListElement { 0051 * label: "Item 2" 0052 * } 0053 * ListElement { 0054 * label: "Item 3" 0055 * } 0056 * } 0057 * //this is optional to make list items animated when reordered 0058 * moveDisplaced: Transition { 0059 * YAnimator { 0060 * duration: Kirigami.Units.longDuration 0061 * easing.type: Easing.InOutQuad 0062 * } 0063 * } 0064 * delegate: Loader { 0065 * width: mainList.width 0066 * sourceComponent: delegateComponent 0067 * } 0068 * } 0069 * ... 0070 * @endcode 0071 * 0072 * @since 2.5 0073 * @inherit QtQuick.Item 0074 */ 0075 Item { 0076 id: root 0077 0078 /** 0079 * @brief This property holds the delegate that will be dragged around. 0080 * 0081 * This item *must* be a child of the actual ListView's delegate. 0082 */ 0083 property Item listItem 0084 0085 /** 0086 * @brief This property holds the ListView that the delegate belong to. 0087 */ 0088 property ListView listView 0089 0090 /** 0091 * @brief This signal is emitted when the drag handle wants to move the item in the model. 0092 * 0093 * The following example does the move in the case a ListModel is used: 0094 * @code 0095 * onMoveRequested: (oldIndex, newIndex) => { 0096 * listModel.move(oldIndex, newIndex, 1); 0097 * } 0098 * @endcode 0099 * @param oldIndex the index the item is currently at 0100 * @param newIndex the index we want to move the item to 0101 */ 0102 signal moveRequested(int oldIndex, int newIndex) 0103 0104 /** 0105 * @brief This signal is emitted when the drag operation is complete and the item has been 0106 * dropped in the new final position. 0107 */ 0108 signal dropped() 0109 0110 implicitWidth: Kirigami.Units.iconSizes.smallMedium 0111 implicitHeight: Kirigami.Units.iconSizes.smallMedium 0112 0113 MouseArea { 0114 id: mouseArea 0115 0116 anchors.fill: parent 0117 0118 drag { 0119 target: listItem 0120 axis: Drag.YAxis 0121 minimumY: 0 0122 } 0123 0124 cursorShape: pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor 0125 preventStealing: true 0126 0127 Kirigami.Icon { 0128 id: internal 0129 0130 anchors.fill: parent 0131 0132 source: "handle-sort" 0133 opacity: mouseArea.pressed || (!Kirigami.Settings.tabletMode && listItem.hovered) ? 1 : 0.6 0134 0135 property int startY 0136 property int mouseDownY 0137 property Item originalParent 0138 property int listItemLastY 0139 property bool draggingUp 0140 0141 function arrangeItem() { 0142 const newIndex = listView.indexAt(1, listView.contentItem.mapFromItem(mouseArea, 0, internal.mouseDownY).y); 0143 0144 if (newIndex > -1 && ((internal.draggingUp && newIndex < index) || (!internal.draggingUp && newIndex > index))) { 0145 root.moveRequested(index, newIndex); 0146 } 0147 } 0148 } 0149 0150 onPressed: mouse => { 0151 internal.originalParent = listItem.parent; 0152 listItem.parent = listView; 0153 listItem.y = internal.originalParent.mapToItem(listItem.parent, listItem.x, listItem.y).y; 0154 internal.originalParent.z = 99; 0155 internal.startY = listItem.y; 0156 internal.listItemLastY = listItem.y; 0157 internal.mouseDownY = mouse.y; 0158 // while dragging listItem's height could change 0159 // we want a const maximumY during the dragging time 0160 mouseArea.drag.maximumY = listView.height - listItem.height; 0161 } 0162 0163 onPositionChanged: mouse => { 0164 if (!pressed || listItem.y === internal.listItemLastY) { 0165 return; 0166 } 0167 0168 internal.draggingUp = listItem.y < internal.listItemLastY 0169 internal.listItemLastY = listItem.y; 0170 0171 internal.arrangeItem(); 0172 0173 // autoscroll when the dragging item reaches the listView's top/bottom boundary 0174 scrollTimer.running = (listView.contentHeight > listView.height) 0175 && ((listItem.y === 0 && !listView.atYBeginning) 0176 || (listItem.y === mouseArea.drag.maximumY && !listView.atYEnd)); 0177 } 0178 0179 onReleased: mouse => dropped() 0180 onCanceled: dropped() 0181 0182 function dropped() { 0183 listItem.y = internal.originalParent.mapFromItem(listItem, 0, 0).y; 0184 listItem.parent = internal.originalParent; 0185 dropAnimation.running = true; 0186 scrollTimer.running = false; 0187 root.dropped(); 0188 } 0189 0190 SequentialAnimation { 0191 id: dropAnimation 0192 YAnimator { 0193 target: listItem 0194 from: listItem.y 0195 to: 0 0196 duration: Kirigami.Units.longDuration 0197 easing.type: Easing.InOutQuad 0198 } 0199 PropertyAction { 0200 target: listItem.parent 0201 property: "z" 0202 value: 0 0203 } 0204 } 0205 0206 Timer { 0207 id: scrollTimer 0208 0209 interval: 50 0210 repeat: true 0211 0212 onTriggered: { 0213 if (internal.draggingUp) { 0214 listView.contentY -= Kirigami.Units.gridUnit; 0215 if (listView.atYBeginning) { 0216 listView.positionViewAtBeginning(); 0217 stop(); 0218 } 0219 } else { 0220 listView.contentY += Kirigami.Units.gridUnit; 0221 if (listView.atYEnd) { 0222 listView.positionViewAtEnd(); 0223 stop(); 0224 } 0225 } 0226 internal.arrangeItem(); 0227 } 0228 } 0229 } 0230 }