forked from openkylin/ukui-panel
fix: 修复拖拽异常问题
This commit is contained in:
parent
7d44c0b226
commit
208d111883
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2024, 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: hxf <hewenfei@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
import QtQml 2.15
|
||||
import QtQuick 2.15
|
||||
|
||||
QtObject {
|
||||
property var windowIdList: []
|
||||
property var windowIcons: {}
|
||||
property var windowTitles: {}
|
||||
property Item currentTaskItem: null
|
||||
}
|
|
@ -1,232 +1,258 @@
|
|||
/*
|
||||
* Copyright (C) 2024, KylinSoft Co., Ltd.
|
||||
*
|
||||
* * 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 <https://www.gnu.org/licenses/>.
|
||||
* *
|
||||
* * Authors: qiqi49 <qiqi@kylinos.cn>
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: qiqi49 <qiqi@kylinos.cn>
|
||||
* hxf <hewenfei@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
import QtQml 2.15
|
||||
import QtQuick 2.12
|
||||
import QtQml.Models 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick 2.15
|
||||
import QtQml.Models 2.15
|
||||
|
||||
import org.ukui.quick.widgets 1.0
|
||||
import org.ukui.panel.taskManager 1.0 as UkuiTaskManager
|
||||
import org.ukui.quick.items 1.0 as Items
|
||||
import org.ukui.quick.platform 1.0 as Platform
|
||||
|
||||
// taskManager列表显示(不包括预览图)
|
||||
ListView {
|
||||
id: baseView
|
||||
property bool isMergeApp: false
|
||||
property int dragStartIndex: 0
|
||||
property bool isBusy: false
|
||||
property int itemSize: (orientation == ListView.Horizontal) ? height : width
|
||||
property var screen
|
||||
property int panelPosition: Widget.container.position
|
||||
property alias viewModel: proxyModel
|
||||
DropArea {
|
||||
id: taskItemListRoot
|
||||
|
||||
signal itemContainsMouse(bool containsMouse, var msg)
|
||||
spacing: 4
|
||||
property var dragedObj: null
|
||||
property alias view: taskItemView
|
||||
property alias viewModel: taskItemProxyModel
|
||||
property bool taskManagerActived: false
|
||||
|
||||
interactive: false
|
||||
// 请求显示预览图
|
||||
signal requestThumbnailView(bool show, TaskItemData data)
|
||||
|
||||
UkuiTaskManager.TaskManagerFilterModel {
|
||||
id: proxyModel
|
||||
id: taskItemProxyModel
|
||||
sourceModel: UkuiTaskManager.TaskManager
|
||||
screen: baseView.screen
|
||||
screen: Widget.container.screen
|
||||
}
|
||||
model: DelegateModel {
|
||||
id: visualModel
|
||||
model: proxyModel
|
||||
delegate: DropArea {
|
||||
id: dropArea
|
||||
property int order: DelegateModel.itemsIndex
|
||||
//非合并状态下激活预览图时 对应的winId
|
||||
property var singleWinId: []
|
||||
|
||||
width: orientation == ListView.Horizontal ? content.width : baseView.itemSize
|
||||
height: orientation == ListView.Horizontal ? baseView.itemSize : content.height
|
||||
Component {
|
||||
id: taskIconComponent
|
||||
Items.Icon {}
|
||||
}
|
||||
|
||||
onWidthChanged: {
|
||||
if(baseView.isBusy) {
|
||||
baseView.forceLayout();
|
||||
DelegateModel {
|
||||
id: taskItemDelegateModel
|
||||
property bool isMergeStatus: (Widget.globalConfig.mergeIcons === 0)
|
||||
property var dragedObject: null
|
||||
|
||||
/**
|
||||
* 删除临时Item
|
||||
*/
|
||||
function removeTempItems() {
|
||||
for (let i = tempItems.count - 1; i >= 0; --i) {
|
||||
const obj = tempItems.get(i);
|
||||
tempItems.remove(i);
|
||||
if (obj.inItems) {
|
||||
taskItemDelegateModel.items.remove(obj.itemsIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
if (drag.y >= baseView.itemSize || drag.y <= 0) {
|
||||
visualModel.items.move(baseView.count - 1, dropArea.order);
|
||||
} else {
|
||||
visualModel.items.move(drag.source.draggableOrder, dropArea.order);
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
if (drag.y >= baseView.itemSize || drag.y <= 0) {
|
||||
visualModel.items.move(drag.source.draggableOrder, baseView.count - 1);
|
||||
/**
|
||||
* 将存起来的Item全部归位,并从persistedItems组中移除
|
||||
*/
|
||||
function resetPersistedItems() {
|
||||
let i = persistedItems.count - 1;
|
||||
for (; i >= 0; --i) {
|
||||
const persistedItemObj = persistedItems.get(i);
|
||||
if (!persistedItemObj.inItems) {
|
||||
// TODO: listview中的数据往前挪可以同步缓存位置,往后挪则位置不会变,需要把临时Item最后出现的位置记下来
|
||||
let tmpItemsIndex = persistedItemObj.itemsIndex;
|
||||
persistedItems.addGroups(i, 1, [items.name]);
|
||||
items.move(persistedItemObj.itemsIndex, tmpItemsIndex, 0);
|
||||
}
|
||||
persistedItems.remove(i, 1);
|
||||
}
|
||||
|
||||
Item {
|
||||
id: draggableItem
|
||||
property int draggableOrder: dropArea.order
|
||||
anchors.fill: parent
|
||||
dragedObject = null;
|
||||
removeTempItems();
|
||||
}
|
||||
|
||||
Drag.supportedActions: Qt.CopyAction
|
||||
Drag.dragType: Drag.Automatic
|
||||
Drag.active: mouseArea.drag.active
|
||||
// 临时生成的用于定位拖拽落点的Items组
|
||||
groups: [
|
||||
DelegateModelGroup { id: tempItems; name: "tempItems" }
|
||||
]
|
||||
|
||||
function grabImage() {
|
||||
var icon = mouseGrabImage.createObject(draggableItem, { width: baseView.itemSize, height: baseView.itemSize, source: model.Icon})
|
||||
icon.grabToImage(function(result) {
|
||||
draggableItem.Drag.imageSource = result.url
|
||||
return result;
|
||||
model: taskItemProxyModel
|
||||
delegate: Item {
|
||||
id: taskItemRoot
|
||||
|
||||
property int dragStartIndex: -1
|
||||
property var icon: model.Icon
|
||||
property bool isDragStatus: false
|
||||
property bool useSingleItem: taskItemDelegateModel.isMergeStatus || CurrentWinIdList.length < 1
|
||||
|
||||
width: taskItemView.isHorizontal ? taskItemLoader.width : taskItemView.width
|
||||
height: taskItemView.isHorizontal ? taskItemView.height : taskItemLoader.height
|
||||
visible: DelegateModel.inItems
|
||||
|
||||
onIconChanged: {
|
||||
generateDragImage();
|
||||
}
|
||||
|
||||
function generateDragImage() {
|
||||
let icon = taskIconComponent.createObject(this, {width: taskItemView.taskItemSize, height: taskItemView.taskItemSize, source: model.Icon});
|
||||
if (icon !== null) {
|
||||
icon.grabToImage(function (result) {
|
||||
taskItemRoot.Drag.imageSource = result.url;
|
||||
icon.destroy();
|
||||
});
|
||||
icon.opacity = 0;
|
||||
icon.visible = false
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
width: orientation == ListView.Horizontal ? content.width : baseView.itemSize
|
||||
height: orientation == ListView.Horizontal ? baseView.itemSize : content.height
|
||||
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
// *********drag*********
|
||||
drag.target: draggableItem
|
||||
drag.onActiveChanged: {
|
||||
if (drag.active) {
|
||||
baseView.isBusy = true;
|
||||
if (baseView.isMergeApp) {
|
||||
contentHide();
|
||||
} else {
|
||||
content.item.toDraggingFinished.connect(contentHide);
|
||||
}
|
||||
|
||||
} else {
|
||||
baseView.isBusy = false;
|
||||
content.opacity = 1;
|
||||
if (baseView.isMergeApp) {
|
||||
dragFinished();
|
||||
} else {
|
||||
content.item.toNormalFinished.connect(dragFinished);
|
||||
}
|
||||
// 拖拽设置, 手动开启拖拽
|
||||
Drag.dragType: Drag.None
|
||||
Drag.hotSpot: Qt.point(taskItemView.taskItemSize/2, taskItemView.taskItemSize/2)
|
||||
// 处理拖拽完成信号
|
||||
Drag.onDragFinished: function (dropAction) {
|
||||
// 拖拽被取消,仅处理内部拖拽
|
||||
if (DelegateModel.inPersistedItems) {
|
||||
const myPObj = taskItemDelegateModel.persistedItems.get(DelegateModel.persistedItemsIndex);
|
||||
taskItemDelegateModel.persistedItems.addGroups(myPObj.persistedItemsIndex, 1, [taskItemDelegateModel.items.name]);
|
||||
// 回到启动拖拽的位置
|
||||
const idx = (dragStartIndex < 0) ? myPObj.itemsIndex : (dragStartIndex >= taskItemDelegateModel.items.count) ? taskItemDelegateModel.items.count : dragStartIndex
|
||||
if (myPObj.itemsIndex !== idx) {
|
||||
taskItemDelegateModel.items.move(myPObj.itemsIndex, idx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function contentHide() {
|
||||
content.opacity = 0;
|
||||
taskItemDelegateModel.resetPersistedItems();
|
||||
taskItemRoot.isDragStatus = false;
|
||||
}
|
||||
|
||||
function startDrag() {
|
||||
// 存起来的被拖拽项目和临时生成的项目都不允许被拖动
|
||||
if (!DelegateModel.inItems || DelegateModel.inPersistedItems || DelegateModel.inTempItems) {
|
||||
return;
|
||||
}
|
||||
|
||||
function dragFinished() {
|
||||
proxyModel.setOrder(visualModel.model.index(baseView.dragStartIndex, 0), dropArea.order);
|
||||
const delegateModel = DelegateModel.model;
|
||||
const itemsIndex = DelegateModel.itemsIndex;
|
||||
dragStartIndex = itemsIndex;
|
||||
// 当前拖拽对象
|
||||
delegateModel.dragedObject = delegateModel.items.get(itemsIndex);
|
||||
// 将被拖拽的项添加到持久化组中
|
||||
delegateModel.items.addGroups(itemsIndex, 1, [delegateModel.persistedItems.name]);
|
||||
|
||||
taskItemRoot.isDragStatus = true;
|
||||
Drag.mimeData = {
|
||||
"text/plain": '{"dragStartIndex":' + dragStartIndex + "}"
|
||||
};
|
||||
Drag.active = true;
|
||||
// 不同的Action鼠标光标不同
|
||||
Drag.startDrag(Qt.MoveAction);
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: taskItemListRoot
|
||||
property: "taskManagerActived"
|
||||
when: model.DemandsAttentionWinIdList.length !== 0
|
||||
value: true
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
// enabled: !taskItemRoot.DelegateModel.inTempItems
|
||||
|
||||
property int lastIndex: -1
|
||||
property string currentWid: ""
|
||||
|
||||
function activeWinId(winId) {
|
||||
// 隐藏预览图
|
||||
taskItemListRoot.requestThumbnailView(false, null);
|
||||
if (UkuiTaskManager.TaskManager.windowIsActivated(winId)) {
|
||||
UkuiTaskManager.TaskManager.execSpecifiedAction(UkuiTaskManager.Action.Minimize, winId);
|
||||
} else {
|
||||
UkuiTaskManager.TaskManager.activateWindow(winId);
|
||||
}
|
||||
}
|
||||
|
||||
// *********mouseEvent*********
|
||||
onPressed: {
|
||||
draggableItem.grabImage();
|
||||
baseView.dragStartIndex = draggableItem.draggableOrder;
|
||||
// 为拖拽截图
|
||||
// onPressed: parent.generateDragImage();
|
||||
|
||||
onPressAndHold: {
|
||||
taskItemRoot.startDrag();
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
onClicked: (mouse) => {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
proxyModel.openMenu(false, model.Actions, baseView);
|
||||
taskItemProxyModel.openMenu(false, model.Actions, taskItemView);
|
||||
} else {
|
||||
if (CurrentWinIdList.length === 0) {
|
||||
visualModel.model.launch(visualModel.model.index(model.index, 0));
|
||||
return;
|
||||
}
|
||||
var index = -1;
|
||||
if (CurrentWinIdList.length === 1) {
|
||||
index = 0;
|
||||
} else if (!isMergeApp) {
|
||||
index = content.item.indexAt(mouseX, mouseY);
|
||||
}
|
||||
|
||||
if (index === -1) {
|
||||
taskItemDelegateModel.model.launch(taskItemDelegateModel.model.index(model.index, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
var currentWinId = CurrentWinIdList[index];
|
||||
if (UkuiTaskManager.TaskManager.windowIsActivated(currentWinId)) {
|
||||
UkuiTaskManager.TaskManager.execSpecifiedAction(UkuiTaskManager.Action.Minimize, currentWinId);
|
||||
let index = -1;
|
||||
if (taskItemDelegateModel.isMergeStatus) {
|
||||
// 轮转
|
||||
if (currentWid !== "") {
|
||||
index = CurrentWinIdList.indexOf(currentWid);
|
||||
if (index < (CurrentWinIdList.length - 1)) {
|
||||
++index;
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
UkuiTaskManager.TaskManager.activateWindow(currentWinId);
|
||||
// 由taskList实现
|
||||
index = taskItemLoader.item.indexAt(mouseX, mouseY);
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
} else if (index >= CurrentWinIdList.length) {
|
||||
index = CurrentWinIdList.length - 1;
|
||||
}
|
||||
|
||||
currentWid = CurrentWinIdList[index];
|
||||
activeWinId(currentWid);
|
||||
}
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
// 设置预览图窗口信息
|
||||
if (CurrentWinIdList.length !== 0 && !baseView.isBusy) {
|
||||
if (isMergeApp) {
|
||||
activeThumbnail(this, true, -1);
|
||||
} else {
|
||||
content.item.itemContainsMouse.connect(activeThumbnail);
|
||||
if (CurrentWinIdList.length > 0) {
|
||||
if (taskItemDelegateModel.isMergeStatus) {
|
||||
taskItemData.windowIdList = CurrentWinIdList;
|
||||
taskItemData.currentTaskItem = taskItemRoot;
|
||||
taskItemListRoot.requestThumbnailView(true, taskItemData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: {
|
||||
activeThumbnail(this, false, -1);
|
||||
taskItemListRoot.requestThumbnailView(false, taskItemData);
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: message
|
||||
property var currentWinIdList: isMergeApp ? model.CurrentWinIdList : singleWinId
|
||||
property var windowTitles: model.WindowTitles
|
||||
property var windowIcons: model.WindowIcons
|
||||
}
|
||||
function activeThumbnail(item, containsMouse, index) {
|
||||
if (containsMouse) {
|
||||
thumbnailView.visualParent = item;
|
||||
if (!isMergeApp) {
|
||||
var wid = model.CurrentWinIdList[index];
|
||||
singleWinId = [wid];
|
||||
}
|
||||
itemContainsMouse(true, message);
|
||||
} else {
|
||||
itemContainsMouse(false, null);
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: content
|
||||
property var currentWinIdList: model.CurrentWinIdList
|
||||
property var modelIcon: model.Icon
|
||||
property var demandsAttentionWinIdList: model.DemandsAttentionWinIdList
|
||||
property var hasActiveWindow: model.HasActiveWindow
|
||||
property var index: model.index
|
||||
property var windowTitles: model.WindowTitles
|
||||
property var windowIcons: model.WindowIcons
|
||||
|
||||
sourceComponent: (isMergeApp || (currentWinIdList.length === 0)) ? appIconComponent : applistComponent
|
||||
onCurrentWinIdListChanged: {
|
||||
if (!currentWinIdList) {
|
||||
currentWinIdList = [];
|
||||
}
|
||||
}
|
||||
Binding {
|
||||
target: baseView
|
||||
property: "panelActive"
|
||||
when: model.DemandsAttentionWinIdList.length !== 0
|
||||
value: true
|
||||
}
|
||||
TaskItemData {
|
||||
id: taskItemData
|
||||
windowIdList: model.CurrentWinIdList
|
||||
windowIcons: model.WindowIcons
|
||||
windowTitles: model.WindowTitles
|
||||
}
|
||||
|
||||
Items.Tooltip {
|
||||
|
@ -235,7 +261,7 @@ ListView {
|
|||
mainText: Name
|
||||
posFollowCursor: false
|
||||
// 只有固定在任务栏的应用显示tooltip
|
||||
active: model.CurrentWinIdList.length === 0
|
||||
active: CurrentWinIdList.length < 1
|
||||
location: {
|
||||
switch(Widget.container.position) {
|
||||
case Items.Types.Bottom:
|
||||
|
@ -250,69 +276,291 @@ ListView {
|
|||
}
|
||||
margin: 6
|
||||
}
|
||||
}
|
||||
|
||||
// 非合并状态 图标+名称
|
||||
Component {
|
||||
id: applistComponent
|
||||
UkuiTaskManager.AppList {
|
||||
height: childrenRect.height
|
||||
width: childrenRect.width
|
||||
Loader {
|
||||
id: taskItemLoader
|
||||
property var taskItemData: model
|
||||
|
||||
itemSize: baseView.itemSize
|
||||
isDragged: draggableItem.Drag.active
|
||||
orientation: baseView.orientation
|
||||
model: CurrentWinIdList
|
||||
function loadedItemRequest(show, windId, item) {
|
||||
taskItemData.windowIdList = [windId];
|
||||
taskItemData.currentTaskItem = item;
|
||||
taskItemListRoot.requestThumbnailView(show, taskItemData);
|
||||
}
|
||||
|
||||
sourceComponent: {
|
||||
if (taskItemRoot.DelegateModel.inTempItems) {
|
||||
return tempTaskitem;
|
||||
}
|
||||
|
||||
if (taskItemRoot.useSingleItem) {
|
||||
return singleTaskItem;
|
||||
}
|
||||
|
||||
return listTaskItem;
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
if (!taskItemRoot.useSingleItem) {
|
||||
item.onRequestThumbnailView.connect(loadedItemRequest);
|
||||
}
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
if (!taskItemRoot.useSingleItem) {
|
||||
item.onRequestThumbnailView.disconnect(loadedItemRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: tempTaskitem
|
||||
Item {
|
||||
width: taskItemView.taskItemSize
|
||||
height: taskItemView.taskItemSize
|
||||
}
|
||||
}
|
||||
|
||||
// 非合并状态 图标+名称
|
||||
Component {
|
||||
id: listTaskItem
|
||||
UkuiTaskManager.AppList {
|
||||
height: childrenRect.height
|
||||
width: childrenRect.width
|
||||
|
||||
itemSize: taskItemView.taskItemSize
|
||||
isDragged: taskItemRoot.isDragStatus
|
||||
orientation: taskItemView.orientation
|
||||
spacing: taskItemView.spacing
|
||||
model: taskItemData.CurrentWinIdList
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: singleTaskItem
|
||||
UkuiTaskManager.AppIcon {
|
||||
width: taskItemView.taskItemSize
|
||||
height: taskItemView.taskItemSize
|
||||
appBackgroud.alpha: mouseArea.containsPress ? 0.10 : mouseArea.containsMouse ? 0.05 : 0
|
||||
appIcon.source: taskItemData.Icon
|
||||
appIcon.scale: mouseArea.containsPress ? 0.9 : 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 合并状态和固定到任务栏 图标
|
||||
Component {
|
||||
id: appIconComponent
|
||||
UkuiTaskManager.AppIcon {
|
||||
height: baseView.itemSize
|
||||
width: baseView.itemSize
|
||||
ListView {
|
||||
id: taskItemView
|
||||
anchors.fill: parent
|
||||
// contentWidth: childrenRect.width
|
||||
// width: childrenRect.width
|
||||
// height: parent.height
|
||||
property bool isHorizontal: orientation === ListView.Horizontal
|
||||
property real taskItemSize: isHorizontal ? taskItemView.height : taskItemView.width
|
||||
|
||||
appBackgroud.alpha: mouseArea.containsPress ? 0.10 : mouseArea.containsMouse ? 0.05 : 0
|
||||
appIcon.source: modelIcon
|
||||
appIcon.scale: mouseArea.containsPress ? 0.9 : 1.0
|
||||
interactive: false
|
||||
|
||||
spacing: 4
|
||||
orientation: (Widget.orientation === Items.Types.Horizontal) ? ListView.Horizontal : ListView.Vertical
|
||||
model: taskItemDelegateModel
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation {
|
||||
properties: "x,y"
|
||||
easing.type: Easing.OutQuad
|
||||
duration: 300
|
||||
}
|
||||
}
|
||||
|
||||
move: Transition {
|
||||
NumberAnimation { properties: "x,y"; duration: 300 }
|
||||
}
|
||||
|
||||
add: Transition {
|
||||
NumberAnimation {
|
||||
id: addAnimation
|
||||
property: taskItemView.isHorizontal ? "y" : "x"
|
||||
from: taskItemView.isHorizontal ? -taskItemView.taskItemSize : taskItemView.taskItemSize
|
||||
to: 0
|
||||
easing.overshoot: 4; easing.amplitude: 2
|
||||
easing.type: Easing.OutBack; duration: 300
|
||||
}
|
||||
}
|
||||
|
||||
remove: Transition {
|
||||
NumberAnimation {
|
||||
id: removeAnimation
|
||||
property: addAnimation.property
|
||||
easing.type: Easing.OutCubic
|
||||
from: 0; to: addAnimation.from
|
||||
duration: 300
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取ListView的坐标对应的ContentItem内部坐标
|
||||
// listview与dropArea的大小需要重合
|
||||
function getContentPoint(localX, localY) {
|
||||
return Qt.point(localX + taskItemView.contentX, localY + taskItemView.contentY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件来源判断
|
||||
* 内部: true
|
||||
* 外部: false
|
||||
*/
|
||||
function isInternalEvent() {
|
||||
return taskItemDelegateModel.dragedObject !== null;
|
||||
}
|
||||
|
||||
// 获取一个Item的中点坐标
|
||||
function getItemMidPoint(item) {
|
||||
return Qt.point(item.x + item.width/2, item.y + item.height/2);
|
||||
}
|
||||
|
||||
// point 是否在item的中点前
|
||||
function beforeMidpoint(item, point) {
|
||||
let midPoint = getItemMidPoint(item);
|
||||
if (taskItemView.orientation === ListView.Horizontal) {
|
||||
return point.x < midPoint.x;
|
||||
} else {
|
||||
return point.y < midPoint.y
|
||||
}
|
||||
}
|
||||
|
||||
// 1.拖拽进入事件
|
||||
// 拖拽进入,需要生成临时Item
|
||||
onEntered: (dragEvent) => {
|
||||
// 1.处理进入拖拽区域时的边缘点情况,避免丢失拖拽事件
|
||||
let enterX = dragEvent.x === width ? dragEvent.x - 1 : dragEvent.x;
|
||||
let enterY = dragEvent.y === height ? dragEvent.y - 1 : dragEvent.y;
|
||||
const contentPoint = getContentPoint(enterX, enterY);
|
||||
|
||||
// 2.删除上次未删除的临时Item,保证只有一个临时Item
|
||||
if (tempItems.count > 0) {
|
||||
taskItemDelegateModel.removeTempItems();
|
||||
}
|
||||
|
||||
// 3.获取进入点下方的Item, 如果为null,则说明拖拽到了空白位置
|
||||
let insertIndex = -1;
|
||||
let pointItem = taskItemView.itemAt(contentPoint.x, contentPoint.y);
|
||||
if (pointItem !== null) {
|
||||
// 4.通过进入点的对象的itemsIndex获取各种数据。
|
||||
insertIndex = pointItem.DelegateModel.itemsIndex;
|
||||
|
||||
// 判断中点位置,确定在插入在前还是后,insertIndex or insertIndex+1
|
||||
const maxIdx = taskItemDelegateModel.items.count - 1;
|
||||
if ((insertIndex > 0) && (insertIndex < maxIdx) && beforeMidpoint(pointItem, contentPoint)) {
|
||||
++insertIndex;
|
||||
}
|
||||
} else {
|
||||
// 5.拖拽进入点是空白区域
|
||||
insertIndex = taskItemDelegateModel.items.count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 4.判断事件来源
|
||||
* 区分拖拽事件的来源,一般有两个来源:
|
||||
* 1.内部拖拽事件,拖拽listview的Item进行位置的调整。
|
||||
* 2.外部事件,将桌面图标拖拽到任务栏上。
|
||||
*/
|
||||
const internal = isInternalEvent();
|
||||
if (internal) {
|
||||
// 从界面移除当前被拖动的项目
|
||||
let draggedObj = taskItemDelegateModel.persistedItems.get(0);
|
||||
// 如果在items组中,那么从可见列表移除
|
||||
if (draggedObj.inItems) {
|
||||
taskItemDelegateModel.items.removeGroups(draggedObj.itemsIndex, 1, ["items"]);
|
||||
}
|
||||
} else {
|
||||
// 暂不支持外部拖拽
|
||||
dragEvent.accepted = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 5.创建临时Item,并将他放到tempItems组中,后续可通过该组删除它
|
||||
taskItemDelegateModel.items.insert(
|
||||
insertIndex,
|
||||
{
|
||||
Name: ""
|
||||
},
|
||||
[taskItemDelegateModel.items.name, "tempItems"]
|
||||
);
|
||||
}
|
||||
|
||||
// 2.拖拽移出事件
|
||||
onExited: {
|
||||
taskItemDelegateModel.removeTempItems();
|
||||
}
|
||||
|
||||
// 3.拖拽移动事件
|
||||
onPositionChanged: (dragEvent) => {
|
||||
if (tempItems.count === 1) {
|
||||
// 落点
|
||||
let currentPoint = getContentPoint(dragEvent.x, dragEvent.y);
|
||||
let targetItem = taskItemView.itemAt(currentPoint.x, currentPoint.y);
|
||||
if (targetItem !== null && !targetItem.DelegateModel.inTempItems) {
|
||||
let sourceIndex = tempItems.get(0).itemsIndex;
|
||||
let targetIndex = targetItem.DelegateModel.itemsIndex;
|
||||
|
||||
const bmp = beforeMidpoint(targetItem, currentPoint);
|
||||
if ((sourceIndex < targetIndex) && bmp) {
|
||||
--targetIndex;
|
||||
} else if ((sourceIndex > targetIndex) && !bmp) {
|
||||
++targetIndex;
|
||||
}
|
||||
|
||||
let moveCount = Math.abs(targetIndex - sourceIndex);
|
||||
if (moveCount === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceIndex < targetIndex) {
|
||||
taskItemDelegateModel.items.move(sourceIndex + 1, sourceIndex, moveCount);
|
||||
} else {
|
||||
taskItemDelegateModel.items.move(targetIndex, targetIndex + 1, moveCount);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: mouseGrabImage
|
||||
Items.ThemeIcon { }
|
||||
}
|
||||
// 4.拖拽放下事件
|
||||
onDropped: (dragEvent) => {
|
||||
// 1.获取丢下点的Index
|
||||
let droppedIndex = -1;
|
||||
if (tempItems.count > 0) {
|
||||
// 默认情况下临时Item对应的位置就是丢下的位置
|
||||
let tempObj = tempItems.get(0);
|
||||
droppedIndex = tempObj.inItems ? tempObj.itemsIndex : taskItemDelegateModel.items.count;
|
||||
} else {
|
||||
// 修正边缘落点情况
|
||||
let enterX = dragEvent.x === width ? dragEvent.x - 1 : dragEvent.x;
|
||||
let enterY = dragEvent.y === height ? dragEvent.y - 1 : dragEvent.y;
|
||||
let contentPoint = getContentPoint(enterX, enterY);
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation {
|
||||
properties: "x,y"
|
||||
easing.type: Easing.OutQuad
|
||||
duration: 250
|
||||
let dropTargetItem = taskItemView.itemAt(contentPoint.x, contentPoint.y);
|
||||
droppedIndex = (dropTargetItem === null) ? taskItemDelegateModel.items.count : dropTargetItem.DelegateModel.itemsIndex;
|
||||
}
|
||||
}
|
||||
|
||||
add: Transition {
|
||||
NumberAnimation {
|
||||
id: addAnimation
|
||||
property: (panelPosition == 2 || panelPosition == 4) ? "y" : "x"
|
||||
from: (panelPosition == 1 || panelPosition == 2) ? -itemSize : itemSize
|
||||
to: 0
|
||||
easing.overshoot: 4; easing.amplitude: 2
|
||||
easing.type: Easing.OutBack; duration: 300
|
||||
}
|
||||
}
|
||||
// 2.清空临时对象
|
||||
taskItemDelegateModel.removeTempItems();
|
||||
|
||||
remove: Transition {
|
||||
NumberAnimation {
|
||||
id: removeAnimation
|
||||
property: addAnimation.property
|
||||
easing.type: Easing.OutCubic
|
||||
from: 0; to: addAnimation.from
|
||||
duration: 300
|
||||
// 3.事件类型
|
||||
if (isInternalEvent()) {
|
||||
let persistedObj = taskItemDelegateModel.dragedObject;
|
||||
// 将存起来的Item放到items组中
|
||||
taskItemDelegateModel.persistedItems.addGroups(0, 1, ["items"])
|
||||
// 挪到正确位置
|
||||
taskItemDelegateModel.items.move(persistedObj.itemsIndex, droppedIndex, 1);
|
||||
// 清空保存的Item
|
||||
taskItemDelegateModel.resetPersistedItems();
|
||||
|
||||
const obj = JSON.parse(dragEvent.text);
|
||||
if (obj !== null) {
|
||||
taskItemProxyModel.setOrder(taskItemDelegateModel.model.index(obj.dragStartIndex, 0), droppedIndex);
|
||||
}
|
||||
} else {
|
||||
// 外部事件,执行外部操作
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2024, KylinSoft Co., Ltd.
|
||||
*
|
||||
* * Copyright (C) 2024, 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 <https://www.gnu.org/licenses/>.
|
||||
* *
|
||||
* * Authors: qiqi49 <qiqi@kylinos.cn>
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: qiqi49 <qiqi@kylinos.cn>
|
||||
* hxf <hewenfei@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -32,7 +32,7 @@ import org.ukui.quick.platform 1.0 as Platform
|
|||
TaskManager {
|
||||
id: taskManager
|
||||
// 任务栏是否激活: 预览图是否显示、是否有高亮显示、是否有拖拽事件
|
||||
property bool panelActive: thumbnailView.visible
|
||||
Widget.active: taskManagerActived || thumbnailView.visible
|
||||
|
||||
state: ""
|
||||
states: [
|
||||
|
@ -75,15 +75,14 @@ TaskManager {
|
|||
}
|
||||
]
|
||||
|
||||
Component.onCompleted: {
|
||||
itemContainsMouse.connect(thumbnailToBeChanged);
|
||||
}
|
||||
|
||||
function thumbnailToBeChanged(containsMouse, thumbnailData) {
|
||||
if (containsMouse) {
|
||||
onRequestThumbnailView: (show, data) => {
|
||||
if (show) {
|
||||
thumbnailView.visualParent = data.currentTaskItem;
|
||||
state = "aboutToShowThumbnail";
|
||||
viewContent.thumbnailData = thumbnailData;
|
||||
viewContent.determineListViewSize();
|
||||
if (viewContent.thumbnailData !== data) {
|
||||
viewContent.thumbnailData = data;
|
||||
viewContent.determineListViewSize();
|
||||
}
|
||||
} else {
|
||||
state = "aboutToHideThumbanil";
|
||||
}
|
||||
|
@ -124,11 +123,11 @@ TaskManager {
|
|||
UkuiTaskManager.ThumbnailWindow {
|
||||
id: viewContent
|
||||
|
||||
property var thumbnailData
|
||||
property var currentWinIdList: thumbnailData ? thumbnailData.currentWinIdList : []
|
||||
property TaskItemData thumbnailData: null
|
||||
property var currentWinIdList: thumbnailData ? thumbnailData.windowIdList : []
|
||||
property var windowTitles: thumbnailData ? thumbnailData.windowTitles : []
|
||||
property var windowIcons: thumbnailData ? thumbnailData.windowIcons : []
|
||||
property bool isHorizontal: taskManager.orientation == ListView.Horizontal
|
||||
property bool isHorizontal: taskManager.view.orientation === ListView.Horizontal
|
||||
property bool hasFocus: viewContent.containsMouse || viewContent.menuVisible
|
||||
|
||||
onHasFocusChanged: {
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2024, KylinSoft Co., Ltd.
|
||||
*
|
||||
* * 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 <https://www.gnu.org/licenses/>.
|
||||
* *
|
||||
* * Authors: qiqi49 <qiqi@kylinos.cn>
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: qiqi49 <qiqi@kylinos.cn>
|
||||
* hxf <hewenfei@kylinos.cn>
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -29,29 +29,14 @@ WidgetItem {
|
|||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
Widget.active: taskManagerView.panelActive
|
||||
|
||||
TaskManagerView {
|
||||
id: taskManagerView
|
||||
anchors.fill: parent
|
||||
orientation: (Widget.orientation == Types.Horizontal) ? ListView.Horizontal : ListView.Vertical
|
||||
screen: Widget.container.screen
|
||||
}
|
||||
|
||||
function dataChangedMonitor(key) {
|
||||
if (key === "mergeIcons") {
|
||||
// mergeIcons value: 1(no merge)
|
||||
taskManagerView.isMergeApp = (Widget.globalConfig.getValue(key) === 0);
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
// init
|
||||
if (Widget.globalConfig.getValue("mergeIcons") === undefined) {
|
||||
Widget.globalConfig.setValue("mergeIcons", 0);
|
||||
if (Widget.globalConfig.mergeIcons === undefined) {
|
||||
Widget.globalConfig.mergeIcons = 0;
|
||||
}
|
||||
|
||||
dataChangedMonitor("mergeIcons");
|
||||
Widget.globalConfig.configChanged.connect(dataChangedMonitor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ Item {
|
|||
color: "#FF9100"
|
||||
z: -1
|
||||
radius: 8
|
||||
visible: demandsAttentionWinIdList.length > 0
|
||||
visible: taskItemData.DemandsAttentionWinIdList.length > 0
|
||||
|
||||
NumberAnimation on opacity {
|
||||
running: demandsAttention.visible
|
||||
|
@ -43,14 +43,14 @@ Item {
|
|||
}
|
||||
UkuiItems.StyleBackground {
|
||||
height: 4
|
||||
width: Math.min(currentWinIdList.length * 8, 16)
|
||||
width: Math.min(taskItemData.CurrentWinIdList.length * 8, 16)
|
||||
radius: 2
|
||||
|
||||
anchors.verticalCenter: backgroud.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
useStyleTransparency: false
|
||||
paletteRole: hasActiveWindow? Platform.Theme.Highlight : Platform.Theme.BrightText
|
||||
alpha: hasActiveWindow? 1 : 0.3
|
||||
paletteRole: taskItemData.HasActiveWindow? Platform.Theme.Highlight : Platform.Theme.BrightText
|
||||
alpha: taskItemData.HasActiveWindow? 1 : 0.3
|
||||
Behavior on width {
|
||||
NumberAnimation { duration: 200 }
|
||||
}
|
||||
|
|
|
@ -28,21 +28,25 @@ import org.ukui.panel.taskManager 1.0 as UkuiTaskManager
|
|||
|
||||
Item {
|
||||
id: root
|
||||
property var orientation
|
||||
property bool isDragged: false
|
||||
property alias model: visualModel.model
|
||||
property alias orientation: normalView.orientation
|
||||
property alias spacing: normalView.spacing
|
||||
property int itemSize: 48
|
||||
|
||||
signal toNormalFinished()
|
||||
signal toDraggingFinished()
|
||||
signal itemContainsMouse(var item, bool containsMouse, int index)
|
||||
signal requestThumbnailView(bool show, string winId, Item item)
|
||||
|
||||
function indexAt(x, y) {
|
||||
if (isDragged) {
|
||||
return -1;
|
||||
} else {
|
||||
return normalView.indexAt(x, y);
|
||||
let idx = normalView.normalViewItemIdx(x, y, normalView.spacing/2, true);
|
||||
if (idx === -1) {
|
||||
idx = normalView.normalViewItemIdx(x, y, normalView.spacing/2, false);
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
DelegateModel {
|
||||
id: visualModel
|
||||
delegate: Package {
|
||||
|
@ -64,7 +68,12 @@ Item {
|
|||
hoverEnabled: true
|
||||
|
||||
onContainsMouseChanged: {
|
||||
itemContainsMouse(this, containsMouse, index)
|
||||
requestThumbnailView(containsMouse, modelData, this);
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
console.log("==list task clicked==")
|
||||
taskItemClicked(modelData);
|
||||
}
|
||||
}
|
||||
UkuiItems.StyleBackground {
|
||||
|
@ -133,7 +142,7 @@ Item {
|
|||
anchors.fill: parent
|
||||
color: "#FF9100"
|
||||
radius: 8
|
||||
visible: demandsAttentionWinIdList.includes(modelData)
|
||||
visible: taskItemData.DemandsAttentionWinIdList.includes(modelData)
|
||||
|
||||
NumberAnimation on opacity {
|
||||
running: demandsAttention.visible
|
||||
|
@ -158,7 +167,7 @@ Item {
|
|||
Layout.maximumWidth: height
|
||||
Layout.fillHeight: true
|
||||
|
||||
source: windowIcons[modelData]
|
||||
source: taskItemData.WindowIcons[modelData]
|
||||
Behavior on scale {
|
||||
NumberAnimation { duration: 200 }
|
||||
}
|
||||
|
@ -172,7 +181,7 @@ Item {
|
|||
Layout.rightMargin: 8
|
||||
visible: !root.isDragged && orientation === ListView.Horizontal
|
||||
|
||||
text: (windowTitles[modelData] === undefined) ? "" : windowTitles[modelData]
|
||||
text: (taskItemData.WindowTitles[modelData] === undefined) ? "" : taskItemData.WindowTitles[modelData]
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideRight
|
||||
|
@ -191,6 +200,14 @@ Item {
|
|||
|
||||
interactive: false
|
||||
spacing: 8
|
||||
|
||||
function normalViewItemIdx(x, y, offset, forward) {
|
||||
if (normalView.orientation === ListView.Horizontal) {
|
||||
return normalView.indexAt(forward ? x - offset : x + offset, y);
|
||||
} else {
|
||||
return normalView.indexAt(x, forward ? y - offset : y + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
|
|
Loading…
Reference in New Issue