Warning, /plasma/plasma-desktop/applets/kicker/package/contents/ui/ItemGridView.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 import QtQuick 2.15 0008 0009 import org.kde.kquickcontrolsaddons 2.0 0010 import org.kde.ksvg 1.0 as KSvg 0011 import org.kde.plasma.components as PlasmaComponents 0012 import org.kde.plasma.extras 2.0 as PlasmaExtras 0013 import org.kde.kirigami 2.20 as Kirigami 0014 0015 FocusScope { 0016 id: itemGrid 0017 0018 signal keyNavLeft 0019 signal keyNavRight 0020 signal keyNavUp 0021 signal keyNavDown 0022 0023 signal itemActivated(int index, string actionId, string argument) 0024 0025 property bool dragEnabled: true 0026 property bool dropEnabled: false 0027 property bool showLabels: true 0028 0029 property alias currentIndex: gridView.currentIndex 0030 property alias currentItem: gridView.currentItem 0031 property alias contentItem: gridView.contentItem 0032 property alias count: gridView.count 0033 property alias model: gridView.model 0034 0035 property alias cellWidth: gridView.cellWidth 0036 property alias cellHeight: gridView.cellHeight 0037 property alias iconSize: gridView.iconSize 0038 0039 property var horizontalScrollBarPolicy: PlasmaComponents.ScrollBar.AlwaysOff 0040 property var verticalScrollBarPolicy: PlasmaComponents.ScrollBar.AsNeeded 0041 0042 onDropEnabledChanged: { 0043 if (!dropEnabled && "dropPlaceHolderIndex" in model) { 0044 model.dropPlaceHolderIndex = -1; 0045 } 0046 } 0047 0048 onFocusChanged: { 0049 if (!focus && !root.keyEventProxy.activeFocus) { 0050 currentIndex = -1; 0051 } 0052 } 0053 0054 function currentRow() { 0055 if (currentIndex === -1) { 0056 return -1; 0057 } 0058 0059 return Math.floor(currentIndex / Math.floor(width / itemGrid.cellWidth)); 0060 } 0061 0062 function currentCol() { 0063 if (currentIndex === -1) { 0064 return -1; 0065 } 0066 0067 return currentIndex - (currentRow() * Math.floor(width / itemGrid.cellWidth)); 0068 } 0069 0070 function lastRow() { 0071 var columns = Math.floor(width / itemGrid.cellWidth); 0072 return Math.ceil(count / columns) - 1; 0073 } 0074 0075 function tryActivate(row, col) { 0076 if (count) { 0077 var columns = Math.floor(width / itemGrid.cellWidth); 0078 var rows = Math.ceil(count / columns); 0079 row = Math.min(row, rows - 1); 0080 col = Math.min(col, columns - 1); 0081 currentIndex = Math.min(row ? ((Math.max(1, row) * columns) + col) 0082 : col, 0083 count - 1); 0084 0085 focus = true; 0086 } 0087 } 0088 0089 function forceLayout() { 0090 gridView.forceLayout(); 0091 } 0092 0093 ActionMenu { 0094 id: actionMenu 0095 0096 onActionClicked: { 0097 visualParent.actionTriggered(actionId, actionArgument); 0098 } 0099 } 0100 0101 DropArea { 0102 id: dropArea 0103 0104 anchors.fill: parent 0105 0106 onPositionChanged: event => { 0107 if (!itemGrid.dropEnabled || gridView.animating || !kicker.dragSource) { 0108 return; 0109 } 0110 0111 var x = Math.max(0, event.x - (width % itemGrid.cellWidth)); 0112 var cPos = mapToItem(gridView.contentItem, x, event.y); 0113 var item = gridView.itemAt(cPos.x, cPos.y); 0114 0115 if (item) { 0116 if (kicker.dragSource.parent === gridView.contentItem) { 0117 if (item !== kicker.dragSource) { 0118 item.GridView.view.model.moveRow(dragSource.itemIndex, item.itemIndex); 0119 } 0120 } else if (kicker.dragSource.GridView.view.model.favoritesModel === itemGrid.model 0121 && !itemGrid.model.isFavorite(kicker.dragSource.favoriteId)) { 0122 var hasPlaceholder = (itemGrid.model.dropPlaceholderIndex !== -1); 0123 0124 itemGrid.model.dropPlaceholderIndex = item.itemIndex; 0125 0126 if (!hasPlaceholder) { 0127 gridView.currentIndex = (item.itemIndex - 1); 0128 } 0129 } 0130 } else if (kicker.dragSource.parent !== gridView.contentItem 0131 && kicker.dragSource.GridView.view.model.favoritesModel === itemGrid.model 0132 && !itemGrid.model.isFavorite(kicker.dragSource.favoriteId)) { 0133 var hasPlaceholder = (itemGrid.model.dropPlaceholderIndex !== -1); 0134 0135 itemGrid.model.dropPlaceholderIndex = hasPlaceholder ? itemGrid.model.count - 1 : itemGrid.model.count; 0136 0137 if (!hasPlaceholder) { 0138 gridView.currentIndex = (itemGrid.model.count - 1); 0139 } 0140 } else { 0141 itemGrid.model.dropPlaceholderIndex = -1; 0142 gridView.currentIndex = -1; 0143 } 0144 } 0145 0146 onExited: { 0147 if ("dropPlaceholderIndex" in itemGrid.model) { 0148 itemGrid.model.dropPlaceholderIndex = -1; 0149 gridView.currentIndex = -1; 0150 } 0151 } 0152 0153 onDropped: { 0154 if (kicker.dragSource && kicker.dragSource.parent !== gridView.contentItem && kicker.dragSource.GridView.view.model.favoritesModel === itemGrid.model) { 0155 itemGrid.model.addFavorite(kicker.dragSource.favoriteId, itemGrid.model.dropPlaceholderIndex); 0156 gridView.currentIndex = -1; 0157 } 0158 } 0159 0160 Timer { 0161 id: resetAnimationDurationTimer 0162 0163 interval: 120 0164 repeat: false 0165 0166 onTriggered: { 0167 gridView.animationDuration = interval - 20; 0168 } 0169 } 0170 0171 PlasmaComponents.ScrollView { 0172 id: scrollArea 0173 0174 anchors.fill: parent 0175 0176 focus: true 0177 0178 PlasmaComponents.ScrollBar.horizontal.policy: itemGrid.horizontalScrollBarPolicy 0179 0180 GridView { 0181 id: gridView 0182 0183 signal itemContainsMouseChanged(bool containsMouse) 0184 0185 property int iconSize: Kirigami.Units.iconSizes.huge 0186 0187 property bool animating: false 0188 property int animationDuration: itemGrid.dropEnabled ? resetAnimationDurationTimer.interval : 0 0189 0190 focus: true 0191 0192 currentIndex: -1 0193 0194 move: Transition { 0195 enabled: itemGrid.dropEnabled 0196 0197 SequentialAnimation { 0198 PropertyAction { target: gridView; property: "animating"; value: true } 0199 0200 NumberAnimation { 0201 duration: gridView.animationDuration 0202 properties: "x, y" 0203 easing.type: Easing.OutQuad 0204 } 0205 0206 PropertyAction { target: gridView; property: "animating"; value: false } 0207 } 0208 } 0209 0210 moveDisplaced: Transition { 0211 enabled: itemGrid.dropEnabled 0212 0213 SequentialAnimation { 0214 PropertyAction { target: gridView; property: "animating"; value: true } 0215 0216 NumberAnimation { 0217 duration: gridView.animationDuration 0218 properties: "x, y" 0219 easing.type: Easing.OutQuad 0220 } 0221 0222 PropertyAction { target: gridView; property: "animating"; value: false } 0223 } 0224 } 0225 0226 keyNavigationWraps: false 0227 boundsBehavior: Flickable.StopAtBounds 0228 0229 delegate: ItemGridDelegate { 0230 showLabel: itemGrid.showLabels 0231 } 0232 0233 highlight: Item { 0234 property bool isDropPlaceHolder: "dropPlaceholderIndex" in itemGrid.model && itemGrid.currentIndex === itemGrid.model.dropPlaceholderIndex 0235 0236 PlasmaExtras.Highlight { 0237 visible: gridView.currentItem && !isDropPlaceHolder 0238 hovered: true 0239 pressed: hoverArea.pressed 0240 0241 anchors.fill: parent 0242 } 0243 0244 KSvg.FrameSvgItem { 0245 visible: gridView.currentItem && isDropPlaceHolder 0246 0247 anchors.fill: parent 0248 0249 imagePath: "widgets/viewitem" 0250 prefix: "selected" 0251 0252 opacity: 0.5 0253 0254 Kirigami.Icon { 0255 anchors { 0256 right: parent.right 0257 rightMargin: parent.margins.right 0258 bottom: parent.bottom 0259 bottomMargin: parent.margins.bottom 0260 } 0261 0262 width: Kirigami.Units.iconSizes.smallMedium 0263 height: width 0264 0265 source: "list-add" 0266 active: false 0267 } 0268 } 0269 } 0270 0271 highlightFollowsCurrentItem: true 0272 highlightMoveDuration: 0 0273 0274 onCurrentIndexChanged: { 0275 if (currentIndex !== -1) { 0276 hoverArea.hoverEnabled = false 0277 focus = true; 0278 } 0279 } 0280 0281 onCountChanged: { 0282 animationDuration = 0; 0283 resetAnimationDurationTimer.start(); 0284 } 0285 0286 onModelChanged: { 0287 currentIndex = -1; 0288 } 0289 0290 Keys.onLeftPressed: event => { 0291 if (itemGrid.currentCol() !== 0) { 0292 event.accepted = true; 0293 moveCurrentIndexLeft(); 0294 } else { 0295 itemGrid.keyNavLeft(); 0296 } 0297 } 0298 0299 Keys.onRightPressed: event => { 0300 var columns = Math.floor(width / cellWidth); 0301 0302 if (itemGrid.currentCol() !== columns - 1 && currentIndex !== count -1) { 0303 event.accepted = true; 0304 moveCurrentIndexRight(); 0305 } else { 0306 itemGrid.keyNavRight(); 0307 } 0308 } 0309 0310 Keys.onUpPressed: event => { 0311 if (itemGrid.currentRow() !== 0) { 0312 event.accepted = true; 0313 moveCurrentIndexUp(); 0314 positionViewAtIndex(currentIndex, GridView.Contain); 0315 } else { 0316 itemGrid.keyNavUp(); 0317 } 0318 } 0319 0320 Keys.onDownPressed: event => { 0321 if (itemGrid.currentRow() < itemGrid.lastRow()) { 0322 // Fix moveCurrentIndexDown()'s lack of proper spatial nav down 0323 // into partial columns. 0324 event.accepted = true; 0325 var columns = Math.floor(width / cellWidth); 0326 var newIndex = currentIndex + columns; 0327 currentIndex = Math.min(newIndex, count - 1); 0328 positionViewAtIndex(currentIndex, GridView.Contain); 0329 } else { 0330 itemGrid.keyNavDown(); 0331 } 0332 } 0333 0334 onItemContainsMouseChanged: containsMouse => { 0335 if (!containsMouse) { 0336 if (!actionMenu.opened) { 0337 gridView.currentIndex = -1; 0338 } 0339 0340 hoverArea.pressX = -1; 0341 hoverArea.pressY = -1; 0342 hoverArea.lastX = -1; 0343 hoverArea.lastY = -1; 0344 hoverArea.pressedItem = null; 0345 hoverArea.hoverEnabled = true; 0346 } 0347 } 0348 } 0349 } 0350 0351 MouseArea { 0352 id: hoverArea 0353 0354 anchors.fill: parent 0355 0356 property int pressX: -1 0357 property int pressY: -1 0358 property int lastX: -1 0359 property int lastY: -1 0360 property Item pressedItem: null 0361 0362 acceptedButtons: Qt.LeftButton | Qt.RightButton 0363 0364 hoverEnabled: true 0365 0366 function updatePositionProperties(x, y) { 0367 // Prevent hover event synthesis in QQuickWindow interfering 0368 // with keyboard navigation by ignoring repeated events with 0369 // identical coordinates. As the work done here would be re- 0370 // dundant in any case, these are safe to ignore. 0371 if (lastX === x && lastY === y) { 0372 return; 0373 } 0374 0375 lastX = x; 0376 lastY = y; 0377 0378 var cPos = mapToItem(gridView.contentItem, x, y); 0379 var item = gridView.itemAt(cPos.x, cPos.y); 0380 0381 if (!item) { 0382 gridView.currentIndex = -1; 0383 pressedItem = null; 0384 } else { 0385 itemGrid.focus = (item.itemIndex !== -1) 0386 gridView.currentIndex = item.itemIndex; 0387 } 0388 0389 return item; 0390 } 0391 0392 onPressed: mouse => { 0393 mouse.accepted = true; 0394 0395 updatePositionProperties(mouse.x, mouse.y); 0396 0397 pressX = mouse.x; 0398 pressY = mouse.y; 0399 0400 if (mouse.button === Qt.RightButton) { 0401 if (gridView.currentItem) { 0402 if (gridView.currentItem.hasActionList) { 0403 var mapped = mapToItem(gridView.currentItem, mouse.x, mouse.y); 0404 gridView.currentItem.openActionMenu(mapped.x, mapped.y); 0405 } 0406 } else { 0407 var mapped = mapToItem(rootItem, mouse.x, mouse.y); 0408 contextMenu.open(mapped.x, mapped.y); 0409 } 0410 } else { 0411 pressedItem = gridView.currentItem; 0412 } 0413 } 0414 0415 onReleased: mouse => { 0416 mouse.accepted = true; 0417 updatePositionProperties(mouse.x, mouse.y); 0418 0419 if (!dragHelper.dragging) { 0420 if (pressedItem) { 0421 if ("trigger" in gridView.model) { 0422 gridView.model.trigger(pressedItem.itemIndex, "", null); 0423 root.toggle(); 0424 } 0425 0426 itemGrid.itemActivated(pressedItem.itemIndex, "", null); 0427 } else if (mouse.button === Qt.LeftButton) { 0428 root.toggle(); 0429 } 0430 } 0431 0432 pressX = pressY = -1; 0433 pressedItem = null; 0434 } 0435 0436 onPositionChanged: mouse => { 0437 var item = pressedItem? pressedItem : updatePositionProperties(mouse.x, mouse.y); 0438 0439 if (gridView.currentIndex !== -1) { 0440 if (itemGrid.dragEnabled && pressX !== -1 && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y)) { 0441 if ("pluginName" in item.m) { 0442 dragHelper.startDrag(kicker, item.url, item.icon, 0443 "text/x-plasmoidservicename", item.m.pluginName); 0444 } else { 0445 dragHelper.startDrag(kicker, item.url, item.icon); 0446 } 0447 0448 kicker.dragSource = item; 0449 0450 pressX = -1; 0451 pressY = -1; 0452 } 0453 } 0454 } 0455 } 0456 } 0457 }