/* * Copyright (C) 2023, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ import QtQuick 2.12 import QtQml.Models 2.1 import QtQuick.Controls 2.5 import org.ukui.menu.core 1.0 import org.ukui.menu.extension 1.0 import AppControls2 1.0 as AppControls2 UkuiMenuExtension { Component.onCompleted: { visualModel.model = extensionData.favoriteAppsModel } MouseArea { id: viewMouseArea anchors.fill: parent hoverEnabled: true AppControls2.StyleBackground { anchors.top: parent.top width: parent.width; height: 1 useStyleTransparent: false alpha: 0.15 paletteRole: Palette.Text visible: favoriteView.contentY > 0 z: 1 } GridView { id: favoriteView anchors.fill: parent anchors.leftMargin: 16 anchors.topMargin: 12 anchors.bottomMargin: 6 cellWidth: itemHeight + spacing; cellHeight: cellWidth property int exchangedStartIndex: 0 property int spacing: 4 property int itemHeight: 104 property int column: Math.floor(width / cellWidth) // 按键导航处理(左右键可以循环) focus: true onActiveFocusChanged: currentIndex = 0 onCountChanged: currentIndex = 0 Keys.onRightPressed: { if(currentIndex === count - 1) { currentIndex = 0; return; } currentIndex++; } Keys.onLeftPressed: { if(currentIndex === 0) { currentIndex = count - 1; return; } currentIndex--; } Keys.onDownPressed: { if(currentIndex > count - 1 - column) { return; } currentIndex = currentIndex + column; } Keys.onUpPressed: { if(currentIndex < column) { return; } currentIndex = currentIndex - column; } ScrollBar.vertical: AppControls2.ScrollBar { id: scrollBar visible: viewMouseArea.containsMouse width: 14; height: favoriteView.height } displaced: Transition { NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad; duration: 200 } } model: DelegateModel { id: visualModel delegate: DropArea { id: delegateRoot property int visualIndex: DelegateModel.itemsIndex width: favoriteView.cellWidth; height: favoriteView.cellHeight onEntered: { visualModel.items.move(drag.source.visualIndex, icon.visualIndex) } Binding { target: icon; property: "visualIndex"; value: visualIndex } focus: true Keys.onReturnPressed: { var data = {"id": model.id}; send(data); } states: State { when: delegateRoot.activeFocus PropertyChanges { target: icon alpha: 0.6 } } AppControls2.StyleBackground { id: icon height: favoriteView.itemHeight; width: height property bool hold: false property int visualIndex: 0 x: 0; y: 0 radius: 8 useStyleTransparent: false scale: icon.hold ? 1.1 :1.0 alpha: control.containsPress ? 0.75 : control.containsMouse ? 0.6 : 0.40 Behavior on scale { NumberAnimation { duration: 300; easing.type: Easing.InOutCubic } } AppControls2.IconLabel { height: icon.height width: icon.width - 14 anchors.centerIn: parent appName: model.name appIcon: model.icon display: Display.TextUnderIcon scale: (control.containsPress && !icon.hold) ? 1.1 : 1.0 ToolTip.visible: textTruncated && control.containsMouse ToolTip.text: model.name ToolTip.delay: 500 Behavior on scale { NumberAnimation { duration: 300; easing.type: Easing.InOutCubic } } } MouseArea { id: control anchors.fill: parent hoverEnabled: true pressAndHoldInterval: 300 acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { if (mouse.button === Qt.RightButton) { visualModel.model.openMenu(index) } else if (mouse.button === Qt.LeftButton) { var data = {"id": model.id}; send(data); } } onPressAndHold: { if (mouse.button === Qt.LeftButton) { drag.target = icon; icon.hold = true; favoriteView.exchangedStartIndex = icon.visualIndex; } } onReleased: { icon.hold = false; drag.target = null; } } onHoldChanged: { if (hold) { favoriteView.interactive = false; } else { favoriteView.interactive = true; visualModel.model.exchangedAppsOrder(favoriteView.exchangedStartIndex, icon.visualIndex); } } Drag.active: control.drag.active Drag.source: icon Drag.hotSpot.x: icon.width / 2 Drag.hotSpot.y: icon.height / 2 Drag.onActiveChanged: { if (Drag.active) { icon.parent = favoriteView; } else { iconResetAnimation.start(); } } ParallelAnimation { id: iconResetAnimation NumberAnimation { target: icon property: "x" to: delegateRoot.x easing.type: Easing.OutQuad duration: 300 } NumberAnimation { target: icon property: "y" to: delegateRoot.y - favoriteView.contentY easing.type: Easing.OutQuad duration: 300 } onFinished: { icon.parent = delegateRoot; icon.x = 0; icon.y = 0; } } } } } } } }