diff --git a/qt6/src/qml.cmake b/qt6/src/qml.cmake index 1fa8f897..0a40268a 100644 --- a/qt6/src/qml.cmake +++ b/qt6/src/qml.cmake @@ -99,6 +99,7 @@ set(QML_DTK_CONTROLS "qml/PlaceholderText.qml" "qml/ControlGroup.qml" "qml/ControlGroupItem.qml" + "qml/DragItemsImage.qml" ) foreach(QML_FILE ${QML_DTK_CONTROLS}) diff --git a/qt6/src/qml/DragItemsImage.qml b/qt6/src/qml/DragItemsImage.qml new file mode 100644 index 00000000..934b362b --- /dev/null +++ b/qt6/src/qml/DragItemsImage.qml @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +import QtQuick 2.15 + +Item { + id: control + property list items + + signal aboutToGrabToImage(Item item) + signal grabToImageFinished(Item item) + + onItemsChanged: function updateGeomotry() { + var w = 0 + var h = 0 + for (var i = 0; i < control.items.length; ++i) { + let item = control.items[i] + w = Math.max(w, item.width) + h = Math.max(h, item.height) + } + control.width = w + 30 + control.height = h * 2 + 30 + } + + function addItem(item) { + if (control.items.include(item)) + return + + items.push(item) + } + + function removeItem(item) { + if (!control.items.include(item)) + return + + var index = control.items.indexOf(item); + if (index !== -1) { + control.items.splice(index, 1); + } + } + + Repeater { + model: control.items.length + delegate: Image { + id: img + anchors.centerIn: parent + antialiasing: true + rotation: index ? (index % 2 === 0 ? 10 : -10) : 0 + opacity: (1 - index * 0.2) + z: -index + + Component.onCompleted: { + let item = control.items[index] + if (!item) + return + + // item.dragActive = true + aboutToGrabToImage(item) + item.grabToImage(function(result) { + img.source = result.url + grabToImageFinished(item) + }) + } + } + } + + RoundButton { + id: number + checked: true + anchors.right: dragItem.right + anchors.top: dragItem.top + anchors.margins: 8 + implicitWidth: 24 + implicitHeight: 24 + text: control.items.length > 1 ? control.items.length : "" + opacity: control.items.length > 1 ? 1 : 0 + } +} diff --git a/qt6/src/qml/ItemDelegate.qml b/qt6/src/qml/ItemDelegate.qml index 19df4924..f8c5a205 100644 --- a/qt6/src/qml/ItemDelegate.qml +++ b/qt6/src/qml/ItemDelegate.qml @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later -import QtQuick 2.11 +import QtQuick import QtQuick.Templates as T import QtQuick.Layouts 1.11 import org.deepin.dtk 1.0 as D @@ -18,6 +18,12 @@ T.ItemDelegate { property Component content property D.Palette checkedTextColor: DS.Style.checkedButton.text property int corners: D.RoundRectangle.TopLeftCorner | D.RoundRectangle.TopRightCorner | D.RoundRectangle.BottomLeftCorner | D.RoundRectangle.BottomRightCorner + property bool dragActive: false + // drag + property bool enableDrag: false + Drag.mimeData: { "text/plain": control.text } + Drag.dragType: Drag.Automatic + function getCornersForBackground(index, count) { if (count <= 1) return D.RoundRectangle.TopLeftCorner | D.RoundRectangle.TopRightCorner | D.RoundRectangle.BottomLeftCorner | D.RoundRectangle.BottomRightCorner @@ -36,7 +42,7 @@ T.ItemDelegate { spacing: DS.Style.control.spacing checkable: true autoExclusive: true - palette.windowText: checked && !control.cascadeSelected && control.backgroundVisible ? D.ColorSelector.checkedTextColor : undefined + palette.windowText: checked && !control.cascadeSelected && control.backgroundVisible && !dragActive? D.ColorSelector.checkedTextColor : undefined D.DciIcon.mode: D.ColorSelector.controlState D.DciIcon.theme: D.ColorSelector.controlTheme @@ -90,7 +96,7 @@ T.ItemDelegate { Loader { anchors.fill: parent - active: checked && !control.cascadeSelected + active: checked && !control.cascadeSelected && !dragActive sourceComponent: HighlightPanel {} } @@ -103,13 +109,60 @@ T.ItemDelegate { corners: control.corners } } + + Loader { + anchors.fill: parent + active: !control.ListView.view && !checked && control.backgroundVisible + sourceComponent: D.RoundRectangle { + color: DS.Style.itemDelegate.normalColor + radius: DS.Style.control.radius + corners: control.corners + } + } + + Loader { + anchors.fill: parent + active: dragActive + sourceComponent: Rectangle { + border.color: Qt.rgba(0, 0, 0, 0.09) + radius: DS.Style.control.radius + } + } + } + + DragHandler { + id: dragHandler + enabled: enableDrag + onActiveChanged: { + if (active) { + let dragItem = control.ListView.view.dragItem + if (!dragItem) + return + + let md = JSON.stringify(dragItem.Drag.mimeData) + + if (md.length > 2) // '{}' + control.Drag.mimeData = dragItem.Drag.mimeData + + dragItem.grabToImage(function(result) { + control.Drag.imageSource = result.url; + control.Drag.hotSpot = Qt.point(dragItem.width / 2, dragItem.height / 2) + control.Drag.active = true + }) + } + } } onHoveredChanged: { - if (checked || control.cascadeSelected || !backgroundVisible) + if (checked || control.cascadeSelected || !backgroundVisible || dragActive) return if (ListView.view) ListView.view.setHoverItem(control.hovered ? control : null) } + + onCheckedChanged: { + if (ListView.view) + ListView.view.updateCheckedItems() + } } diff --git a/qt6/src/qml/ListView.qml b/qt6/src/qml/ListView.qml index d6952531..562839d3 100644 --- a/qt6/src/qml/ListView.qml +++ b/qt6/src/qml/ListView.qml @@ -2,8 +2,9 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later -import QtQuick 2.11 +import QtQuick 2.15 import QtQuick.Templates as T +import org.deepin.dtk 1.0 as D import org.deepin.dtk.style 1.0 as DS import org.deepin.dtk.private 1.0 as P @@ -12,16 +13,8 @@ ListView { property int duration: 100 property bool bgVisible: false property Item hoveredItem - - onContentXChanged: { - if (hoveredItem && hoveredItem.hovered && background) - background.x = hoveredItem.x - contentX - } - - onContentYChanged: { - if (hoveredItem && hoveredItem.hovered && background) - background.y = hoveredItem.y - contentY - } + property list checkedItems + property alias dragItem: dragItem function setHoverItem(item) { if (item) { @@ -39,6 +32,42 @@ ListView { } } + function updateCheckedItems() { + var items = [] + for (var i = 0; i < count; ++i) { + let item = itemAtIndex(i) + if (item && item.checked) { + items.push(item) + } + } + + checkedItems = items + } + + DragItemsImage { + id: dragItem + items: checkedItems + visible: Drag.active + // Drag.mimeData: {"text/plain": ""} + + onAboutToGrabToImage: function(item) { + item.dragActive = true + } + onGrabToImageFinished: function(item) { + item.dragActive = false + } + } + + onContentXChanged: { + if (hoveredItem && hoveredItem.hovered && background) + background.x = hoveredItem.x - contentX + } + + onContentYChanged: { + if (hoveredItem && hoveredItem.hovered && background) + background.y = hoveredItem.y - contentY + } + // ItemDelegate hover item0 ==> item1, add timer ignore [item0.unhovered] // item0.hovered, item0.unhovered, item1.hovered Timer {