diff --git a/src/effects/desktopgrid/qml/DesktopView.qml b/src/effects/desktopgrid/qml/DesktopView.qml index 242e54cc14..4d88ac9e99 100644 --- a/src/effects/desktopgrid/qml/DesktopView.qml +++ b/src/effects/desktopgrid/qml/DesktopView.qml @@ -105,9 +105,6 @@ DropArea { animationEnabled: container.animationEnabled organized: container.organized layout: effect.layout - supportsCloseWindows: false - supportsDragUpGesture: false - showCaptions: false model: KWinComponents.ClientFilterModel { activity: KWinComponents.Workspace.currentActivity desktop: desktopView.desktop @@ -117,6 +114,11 @@ DropArea { ~KWinComponents.ClientFilterModel.Desktop & ~KWinComponents.ClientFilterModel.Notification; } + delegate: WindowHeapDelegate { + windowHeap: heap + closeButtonVisible: false + windowTitleVisible: false + } onActivated: effect.deactivate(effect.animationDuration); onWindowClicked: { if (eventPoint.event.button !== Qt.MiddleButton) { diff --git a/src/effects/overview/qml/ScreenView.qml b/src/effects/overview/qml/ScreenView.qml index a2758e364b..17bbbbf6b7 100644 --- a/src/effects/overview/qml/ScreenView.qml +++ b/src/effects/overview/qml/ScreenView.qml @@ -11,6 +11,7 @@ import org.kde.kwin.private.effects 1.0 import org.kde.milou 0.3 as Milou import org.kde.plasma.components 3.0 as PC3 import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.kirigami 2.12 as Kirigami FocusScope { id: container @@ -183,13 +184,11 @@ FocusScope { id: heap visible: !(container.organized && searchField.text) anchors.fill: parent - layout: effect.layout + layoutMode: effect.layout padding: PlasmaCore.Units.largeSpacing animationDuration: effect.animationDuration animationEnabled: container.animationEnabled organized: container.organized - supportsCloseWindows: true - supportsDragUpGesture: true onWindowClicked: { if (eventPoint.event.button !== Qt.MiddleButton) { return; @@ -207,6 +206,22 @@ FocusScope { ~KWinComponents.ClientFilterModel.Notification; } onActivated: effect.deactivate(); + delegate: WindowHeapDelegate { + windowHeap: heap + + targetScale: { + var localPressPosition = dragHandler.centroid.scenePressPosition.y - heap.expoLayout.Kirigami.ScenePosition.y; + if (localPressPosition == 0) { + return 0.1 + } else { + var localPosition = dragHandler.centroid.scenePosition.y - heap.expoLayout.Kirigami.ScenePosition.y; + return Math.max(0.1, Math.min(localPosition / localPressPosition, 1)) + } + } + + opacity: 1 - downGestureProgress + onDownGestureTriggered: client.closeWindow() + } } Milou.ResultsView { @@ -246,7 +261,7 @@ FocusScope { Behavior on opacity { enabled: !container.effect.gestureInProgress - NumberAnimation { duration: animationDuration; easing.type: Easing.OutCubic } + NumberAnimation { duration: effect.animationDuration; easing.type: Easing.OutCubic } } } } diff --git a/src/effects/private/qml/WindowHeap.qml b/src/effects/private/qml/WindowHeap.qml index a87d07751c..9a3f9075fa 100644 --- a/src/effects/private/qml/WindowHeap.qml +++ b/src/effects/private/qml/WindowHeap.qml @@ -22,11 +22,10 @@ FocusScope { Down } - property bool supportsCloseWindows: false - property bool supportsDragUpGesture: false - property bool showCaptions: true property alias model: windowsRepeater.model + property alias delegate: windowsRepeater.delegate property alias layout: expoLayout.mode + property alias expoLayout: expoLayout property int selectedIndex: -1 property int animationDuration: PlasmaCore.Units.longDuration property bool animationEnabled: false @@ -110,369 +109,7 @@ FocusScope { Repeater { id: windowsRepeater - - Item { - id: thumb - - required property QtObject client - required property int index - - readonly property bool selected: heap.selectedIndex == index - readonly property bool hidden: { - if (heap.showOnly === "activeClass") { - return heap.activeClass !== String(thumb.client.resourceName); // thumb.client.resourceName is not an actual String as comes from a QByteArray so === would fail - } else { - return heap.showOnly.length && heap.showOnly.indexOf(client.internalId) == -1; - } - } - - Component.onCompleted: { - if (thumb.client.active) { - heap.activeClass = thumb.client.resourceName; - } - } - Connections { - target: thumb.client - function onActiveChanged() { - if (thumb.client.active) { - heap.activeClass = thumb.client.resourceName; - } - } - } - - state: { - if (effect.gestureInProgress) { - return "partial"; - } - if (heap.effectiveOrganized) { - return hidden ? "active-hidden" : "active"; - } - return client.minimized ? "initial-minimized" : "initial"; - } - - visible: opacity > 0 - z: thumb.activeDragHandler.active ? 100 : client.stackingOrder - - component TweenBehavior : Behavior { - enabled: thumb.state !== "partial" && heap.animationEnabled && !thumb.activeDragHandler.active - NumberAnimation { - duration: heap.animationDuration - easing.type: Easing.OutCubic - } - } - - TweenBehavior on x {} - TweenBehavior on y {} - TweenBehavior on width {} - TweenBehavior on height {} - - KWinComponents.WindowThumbnailItem { - id: thumbSource - wId: thumb.client.internalId - state: thumb.activeDragHandler.active ? "drag" : "normal" - readonly property QtObject screen: targetScreen - readonly property QtObject client: thumb.client - - Drag.active: thumb.activeDragHandler.active - Drag.source: thumb.client - Drag.hotSpot: Qt.point( - thumb.activeDragHandler.centroid.pressPosition.x * thumb.activeDragHandler.targetScale, - thumb.activeDragHandler.centroid.pressPosition.y * thumb.activeDragHandler.targetScale) - - onXChanged: effect.checkItemDraggedOutOfScreen(thumbSource) - onYChanged: effect.checkItemDraggedOutOfScreen(thumbSource) - - states: [ - State { - name: "normal" - PropertyChanges { - target: thumbSource - x: 0 - y: 0 - width: thumb.width - height: thumb.height - } - }, - State { - name: "drag" - PropertyChanges { - target: thumbSource - x: -thumb.activeDragHandler.centroid.pressPosition.x * thumb.activeDragHandler.targetScale + - thumb.activeDragHandler.centroid.position.x - y: -thumb.activeDragHandler.centroid.pressPosition.y * thumb.activeDragHandler.targetScale + - thumb.activeDragHandler.centroid.position.y - width: cell.width * thumb.activeDragHandler.targetScale - height: cell.height * thumb.activeDragHandler.targetScale - opacity: thumb.activeDragHandler.targetOpacity - } - } - ] - transitions: Transition { - to: "normal" - enabled: heap.animationEnabled - NumberAnimation { - duration: heap.animationDuration - properties: "x, y, width, height, opacity" - easing.type: Easing.OutCubic - } - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton - cursorShape: thumb.activeDragHandler.active ? Qt.ClosedHandCursor : Qt.ArrowCursor - } - } - - PC3.Label { - anchors.fill: thumbSource - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - text: i18nd("kwin_effects", "Drag Down To Close") - opacity: 1 - thumbSource.opacity - visible: !thumb.hidden - } - - PlasmaCore.IconItem { - id: icon - usesPlasmaTheme: false - width: PlasmaCore.Units.iconSizes.large - height: width - source: thumb.client.icon - anchors.horizontalCenter: thumbSource.horizontalCenter - anchors.bottom: thumbSource.bottom - anchors.bottomMargin: -height / 4 - visible: !thumb.hidden && !activeDragHandler.active - - - PC3.Label { - id: caption - visible: heap.showCaptions - width: Math.min(implicitWidth, thumbSource.width) - anchors.top: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - elide: Text.ElideRight - text: thumb.client.caption - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - } - - ExpoCell { - id: cell - layout: expoLayout - enabled: !thumb.hidden - naturalX: thumb.client.x - targetScreen.geometry.x - expoLayout.Kirigami.ScenePosition.x - naturalY: thumb.client.y - targetScreen.geometry.y - expoLayout.Kirigami.ScenePosition.y - naturalWidth: thumb.client.width - naturalHeight: thumb.client.height - persistentKey: thumb.client.internalId - bottomMargin: icon.height / 4 + caption.height - } - - states: [ - State { - name: "initial" - PropertyChanges { - target: thumb - x: thumb.client.x - targetScreen.geometry.x - (heap.absolutePositioning ? expoLayout.Kirigami.ScenePosition.x : 0) - y: thumb.client.y - targetScreen.geometry.y - (heap.absolutePositioning ? expoLayout.Kirigami.ScenePosition.y : 0) - width: thumb.client.width - height: thumb.client.height - } - PropertyChanges { - target: icon - opacity: 0 - } - PropertyChanges { - target: closeButton - opacity: 0 - } - }, - State { - name: "partial" - PropertyChanges { - target: thumb - x: (thumb.client.x - targetScreen.geometry.x - (heap.absolutePositioning ? expoLayout.Kirigami.ScenePosition.x : 0)) * (1 - effect.partialActivationFactor) + cell.x * effect.partialActivationFactor - y: (thumb.client.y - targetScreen.geometry.y - (heap.absolutePositioning ? expoLayout.Kirigami.ScenePosition.y : 0)) * (1 - effect.partialActivationFactor) + cell.y * effect.partialActivationFactor - width: thumb.client.width * (1 - effect.partialActivationFactor) + cell.width * effect.partialActivationFactor - height: thumb.client.height * (1 - effect.partialActivationFactor) + cell.height * effect.partialActivationFactor - opacity: thumb.client.minimized ? effect.partialActivationFactor : 1 - } - PropertyChanges { - target: icon - opacity: effect.partialActivationFactor - } - PropertyChanges { - target: closeButton - opacity: effect.partialActivationFactor - } - }, - State { - name: "initial-minimized" - extend: "initial" - PropertyChanges { - target: thumb - opacity: 0 - } - PropertyChanges { - target: icon - opacity: 0 - } - PropertyChanges { - target: closeButton - opacity: 0 - } - }, - State { - name: "active" - PropertyChanges { - target: thumb - x: cell.x - y: cell.y - width: cell.width - height: cell.height - } - PropertyChanges { - target: icon - opacity: 1 - } - PropertyChanges { - target: closeButton - opacity: 1 - } - }, - State { - name: "active-hidden" - extend: "active" - PropertyChanges { - target: thumb - opacity: 0 - } - } - ] - - transitions: Transition { - to: "initial, active, active-hidden" - enabled: heap.animationEnabled - NumberAnimation { - duration: heap.animationDuration - properties: "x, y, width, height, opacity" - easing.type: Easing.InOutCubic - } - } - - - PlasmaCore.FrameSvgItem { - anchors.fill: parent - anchors.margins: -PlasmaCore.Units.smallSpacing - imagePath: "widgets/viewitem" - prefix: "hover" - z: -1 - visible: !thumb.activeDragHandler.active && (hoverHandler.hovered || selected) - } - - HoverHandler { - id: hoverHandler - onHoveredChanged: if (hovered != selected) { - heap.resetSelected(); - } - } - - TapHandler { - acceptedButtons: Qt.LeftButton - onTapped: { - KWinComponents.Workspace.activeClient = thumb.client; - heap.activated(); - } - } - - TapHandler { - acceptedPointerTypes: PointerDevice.GenericPointer | PointerDevice.Pen - acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton - onTapped: { - heap.windowClicked(thumb.client, eventPoint) - } - } - - component DragManager : DragHandler { - id: dragHandler - target: null - grabPermissions: PointerHandler.CanTakeOverFromAnything - - readonly property double targetScale: { - if (!heap.supportsDragUpGesture) { - return 1; - } - const localPressPosition = centroid.scenePressPosition.y - expoLayout.Kirigami.ScenePosition.y; - if (localPressPosition == 0) { - return 0.1 - } else { - const localPosition = centroid.scenePosition.y - expoLayout.Kirigami.ScenePosition.y; - return Math.max(0.1, Math.min(localPosition / localPressPosition, 1)) - } - } - - onActiveChanged: { - heap.dragActive = active; - if (active) { - thumb.activeDragHandler = dragHandler; - } else { - thumbSource.Drag.drop(); - let globalPos = targetScreen.mapToGlobal(centroid.scenePosition); - effect.checkItemDroppedOutOfScreen(globalPos, thumbSource); - } - } - } - property DragManager activeDragHandler: dragHandler - DragManager { - id: dragHandler - readonly property double targetOpacity: 1 - acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad | PointerDevice.Stylus - } - DragManager { - id: touchDragHandler - acceptedDevices: PointerDevice.TouchScreen - readonly property double targetOpacity: { - if (!heap.supportsCloseWindows) { - return 1; - } - const startDistance = heap.Kirigami.ScenePosition.y + heap.height - centroid.scenePressPosition.y; - const localPosition = heap.Kirigami.ScenePosition.y + heap.height - centroid.scenePosition.y; - return Math.min(localPosition / startDistance, 1); - } - - onActiveChanged: { - if (!active) { - if (heap.supportsCloseWindows && targetOpacity < 0.4) { - thumb.client.closeWindow(); - } - } - } - } - - PC3.Button { - id: closeButton - visible: heap.supportsCloseWindows && (hoverHandler.hovered || Kirigami.Settings.tabletMode || Kirigami.Settings.hasTransientTouchInput) && thumb.client.closeable && !dragHandler.active - anchors { - right: thumbSource.right - rightMargin: PlasmaCore.Units.smallSpacing - top: thumbSource.top - topMargin: PlasmaCore.Units.smallSpacing - } - LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft - icon.name: "window-close" - implicitWidth: PlasmaCore.Units.iconSizes.medium - implicitHeight: implicitWidth - onClicked: thumb.client.closeWindow(); - } - - Component.onDestruction: { - if (selected) { - heap.resetSelected(); - } - } - } + delegate: WindowHeapDelegate {} } } diff --git a/src/effects/private/qml/WindowHeapDelegate.qml b/src/effects/private/qml/WindowHeapDelegate.qml new file mode 100644 index 0000000000..e318c9e9fb --- /dev/null +++ b/src/effects/private/qml/WindowHeapDelegate.qml @@ -0,0 +1,380 @@ +/* + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +import QtQuick 2.12 +import QtQuick.Window 2.12 +import org.kde.kirigami 2.12 as Kirigami +import org.kde.kwin 3.0 as KWinComponents +import org.kde.kwin.private.effects 1.0 +import org.kde.plasma.components 3.0 as PC3 +import org.kde.plasma.core 2.0 as PlasmaCore + + +Item { + id: thumb + + required property QtObject client + required property int index + required property Item windowHeap + + readonly property alias dragHandler: thumb.activeDragHandler + readonly property bool selected: thumb.windowHeap.selectedIndex == index + //TODO: move? + readonly property bool hidden: { + if (thumb.windowHeap.showOnly === "activeClass") { + return thumb.windowHeap.activeClass !== String(thumb.client.resourceName); // thumb.client.resourceName is not an actual String as comes from a QByteArray so === would fail + } else { + return thumb.windowHeap.showOnly.length && thumb.windowHeap.showOnly.indexOf(client.internalId) == -1; + } + } + + // Show a close button on this thumbnail + property bool closeButtonVisible: true + // Show a text label under this thumbnail + property bool windowTitleVisible: true + + //scale up and down the whole thumbnail without affecting layouting + property real targetScale: 1.0 + + // Swipe down gesture by touch, in some effects will close the window + readonly property alias downGestureProgress: touchDragHandler.downGestureProgress + signal downGestureTriggered() + + + + Component.onCompleted: { + if (thumb.client.active) { + thumb.windowHeap.activeClass = thumb.client.resourceName; + } + } + Connections { + target: thumb.client + function onActiveChanged() { + if (thumb.client.active) { + thumb.windowHeap.activeClass = thumb.client.resourceName; + } + } + } + + state: { + if (effect.gestureInProgress) { + return "partial"; + } + if (thumb.windowHeap.effectiveOrganized) { + return hidden ? "active-hidden" : "active"; + } + return client.minimized ? "initial-minimized" : "initial"; + } + + visible: opacity > 0 + z: thumb.activeDragHandler.active ? 100 : client.stackingOrder + + component TweenBehavior : Behavior { + enabled: thumb.state !== "partial" && thumb.windowHeap.animationEnabled && !thumb.activeDragHandler.active + NumberAnimation { + duration: thumb.windowHeap.animationDuration + easing.type: Easing.OutCubic + } + } + + TweenBehavior on x {} + TweenBehavior on y {} + TweenBehavior on width {} + TweenBehavior on height {} + + KWinComponents.WindowThumbnailItem { + id: thumbSource + wId: thumb.client.internalId + state: thumb.activeDragHandler.active ? "drag" : "normal" + readonly property QtObject screen: targetScreen + readonly property QtObject client: thumb.client + + Drag.active: thumb.activeDragHandler.active + Drag.source: thumb.client + Drag.hotSpot: Qt.point( + thumb.activeDragHandler.centroid.pressPosition.x * thumb.targetScale, + thumb.activeDragHandler.centroid.pressPosition.y * thumb.targetScale) + + onXChanged: effect.checkItemDraggedOutOfScreen(thumbSource) + onYChanged: effect.checkItemDraggedOutOfScreen(thumbSource) + + states: [ + State { + name: "normal" + PropertyChanges { + target: thumbSource + x: 0 + y: 0 + width: thumb.width * thumb.targetScale + height: thumb.height * thumb.targetScale + } + }, + State { + name: "drag" + PropertyChanges { + target: thumbSource + x: -thumb.activeDragHandler.centroid.pressPosition.x * thumb.targetScale + + thumb.activeDragHandler.centroid.position.x + y: -thumb.activeDragHandler.centroid.pressPosition.y * thumb.targetScale + + thumb.activeDragHandler.centroid.position.y + width: cell.width * thumb.targetScale + height: cell.height * thumb.targetScale + opacity: thumb.activeDragHandler.targetOpacity + } + } + ] + transitions: Transition { + to: "normal" + enabled: thumb.windowHeap.animationEnabled + NumberAnimation { + duration: thumb.windowHeap.animationDuration + properties: "x, y, width, height, opacity" + easing.type: Easing.OutCubic + } + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: thumb.activeDragHandler.active ? Qt.ClosedHandCursor : Qt.ArrowCursor + } + } + + PC3.Label { + anchors.fill: thumbSource + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: i18nd("kwin_effects", "Drag Down To Close") + opacity: 1 - thumbSource.opacity + visible: !thumb.hidden + } + + PlasmaCore.IconItem { + id: icon + width: PlasmaCore.Units.iconSizes.large + height: width + source: thumb.client.icon + anchors.horizontalCenter: thumbSource.horizontalCenter + anchors.bottom: thumbSource.bottom + anchors.bottomMargin: -height / 4 + visible: !thumb.hidden && !activeDragHandler.active + + + PC3.Label { + id: caption + visible: thumb.windowTitleVisible + width: Math.min(implicitWidth, thumbSource.width) + anchors.top: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + elide: Text.ElideRight + text: thumb.client.caption + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + ExpoCell { + id: cell + layout: windowHeap.expoLayout + enabled: !thumb.hidden + naturalX: thumb.client.x - targetScreen.geometry.x - windowHeap.expoLayout.Kirigami.ScenePosition.x + naturalY: thumb.client.y - targetScreen.geometry.y - windowHeap.expoLayout.Kirigami.ScenePosition.y + naturalWidth: thumb.client.width + naturalHeight: thumb.client.height + persistentKey: thumb.client.internalId + bottomMargin: icon.height / 4 + caption.height + } + + states: [ + State { + name: "initial" + PropertyChanges { + target: thumb + x: thumb.client.x - targetScreen.geometry.x - (thumb.windowHeap.absolutePositioning ? windowHeap.expoLayout.Kirigami.ScenePosition.x : 0) + y: thumb.client.y - targetScreen.geometry.y - (thumb.windowHeap.absolutePositioning ? windowHeap.expoLayout.Kirigami.ScenePosition.y : 0) + width: thumb.client.width + height: thumb.client.height + } + PropertyChanges { + target: icon + opacity: 0 + } + PropertyChanges { + target: closeButton + opacity: 0 + } + }, + State { + name: "partial" + PropertyChanges { + target: thumb + x: (thumb.client.x - targetScreen.geometry.x - (thumb.windowHeap.absolutePositioning ? windowHeap.expoLayout.Kirigami.ScenePosition.x : 0)) * (1 - effect.partialActivationFactor) + cell.x * effect.partialActivationFactor + y: (thumb.client.y - targetScreen.geometry.y - (thumb.windowHeap.absolutePositioning ? windowHeap.expoLayout.Kirigami.ScenePosition.y : 0)) * (1 - effect.partialActivationFactor) + cell.y * effect.partialActivationFactor + width: thumb.client.width * (1 - effect.partialActivationFactor) + cell.width * effect.partialActivationFactor + height: thumb.client.height * (1 - effect.partialActivationFactor) + cell.height * effect.partialActivationFactor + opacity: thumb.client.minimized ? effect.partialActivationFactor : 1 + } + PropertyChanges { + target: icon + opacity: effect.partialActivationFactor + } + PropertyChanges { + target: closeButton + opacity: effect.partialActivationFactor + } + }, + State { + name: "initial-minimized" + extend: "initial" + PropertyChanges { + target: thumb + opacity: 0 + } + PropertyChanges { + target: icon + opacity: 0 + } + PropertyChanges { + target: closeButton + opacity: 0 + } + }, + State { + name: "active" + PropertyChanges { + target: thumb + x: cell.x + y: cell.y + width: cell.width + height: cell.height + } + PropertyChanges { + target: icon + opacity: 1 + } + PropertyChanges { + target: closeButton + opacity: 1 + } + }, + State { + name: "active-hidden" + extend: "active" + PropertyChanges { + target: thumb + opacity: 0 + } + } + ] + + transitions: Transition { + to: "initial, active, active-hidden" + enabled: thumb.windowHeap.animationEnabled + NumberAnimation { + duration: thumb.windowHeap.animationDuration + properties: "x, y, width, height, opacity" + easing.type: Easing.InOutCubic + } + } + + + PlasmaCore.FrameSvgItem { + anchors.fill: parent + anchors.margins: -PlasmaCore.Units.smallSpacing + imagePath: "widgets/viewitem" + prefix: "hover" + z: -1 + visible: !thumb.activeDragHandler.active && (hoverHandler.hovered || selected) + } + + HoverHandler { + id: hoverHandler + onHoveredChanged: if (hovered != selected) { + thumb.windowHeap.resetSelected(); + } + } + + TapHandler { + acceptedButtons: Qt.LeftButton + onTapped: { + KWinComponents.Workspace.activeClient = thumb.client; + thumb.windowHeap.activated(); + } + } + + TapHandler { + acceptedPointerTypes: PointerDevice.GenericPointer | PointerDevice.Pen + acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton + onTapped: { + thumb.windowHeap.windowClicked(thumb.client, eventPoint) + } + } + + component DragManager : DragHandler { + id: dragHandler + target: null + grabPermissions: PointerHandler.CanTakeOverFromAnything + + onActiveChanged: { + thumb.windowHeap.dragActive = active; + if (active) { + thumb.activeDragHandler = dragHandler; + } else { + thumbSource.Drag.drop(); + var globalPos = targetScreen.mapToGlobal(centroid.scenePosition); + effect.checkItemDroppedOutOfScreen(globalPos, thumbSource); + } + } + } + property DragManager activeDragHandler: dragHandler + DragManager { + id: dragHandler + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad | PointerDevice.Stylus + } + DragManager { + id: touchDragHandler + acceptedDevices: PointerDevice.TouchScreen + readonly property double downGestureProgress: { + if (!active) { + return 0.0; + } + + const startDistance = thumb.windowHeap.Kirigami.ScenePosition.y + thumb.windowHeap.height - centroid.scenePressPosition.y; + const localPosition = thumb.windowHeap.Kirigami.ScenePosition.y + thumb.windowHeap.height - centroid.scenePosition.y; + return Math.min(startDistance / localPosition, 1); + } + + onActiveChanged: { + if (!active) { + if (downGestureProgress > 0.6) { + thumb.downGestureTriggered(); + } + } + } + } + + PC3.Button { + id: closeButton + visible: thumb.closeButtonVisible && (hoverHandler.hovered || Kirigami.Settings.tabletMode || Kirigami.Settings.hasTransientTouchInput) && thumb.client.closeable && !dragHandler.active + anchors { + right: thumbSource.right + rightMargin: PlasmaCore.Units.smallSpacing + top: thumbSource.top + topMargin: PlasmaCore.Units.smallSpacing + } + LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft + icon.name: "window-close" + implicitWidth: PlasmaCore.Units.iconSizes.medium + implicitHeight: implicitWidth + onClicked: thumb.client.closeWindow(); + } + + Component.onDestruction: { + if (selected) { + thumb.windowHeap.resetSelected(); + } + } +} diff --git a/src/effects/private/qmldir b/src/effects/private/qmldir index ee0ffb03a2..4dd3210d45 100644 --- a/src/effects/private/qmldir +++ b/src/effects/private/qmldir @@ -8,3 +8,4 @@ plugin effectsplugin classname EffectKitExtensionPlugin WindowHeap 1.0 WindowHeap.qml +WindowHeapDelegate 1.0 WindowHeapDelegate.qml diff --git a/src/effects/windowview/qml/main.qml b/src/effects/windowview/qml/main.qml index c22d1ba6e2..ce56390177 100644 --- a/src/effects/windowview/qml/main.qml +++ b/src/effects/windowview/qml/main.qml @@ -119,8 +119,7 @@ Item { animationEnabled: container.animationEnabled organized: container.organized showOnly: container.effect.mode === WindowView.ModeWindowClass ? "activeClass" : selectedIds - layout: effect.layout - supportsCloseWindows: true + layoutMode: effect.layout onWindowClicked: { if (eventPoint.event.button !== Qt.MiddleButton) { return; @@ -138,6 +137,11 @@ Item { ~KWinComponents.ClientFilterModel.Desktop & ~KWinComponents.ClientFilterModel.Notification; } + delegate: WindowHeapDelegate { + windowHeap: heap + opacity: 1 - downGestureProgress + onDownGestureTriggered: client.closeWindow() + } onActivated: effect.deactivate(animationDuration); } }