Commit cd02c60f authored by Marco Martin's avatar Marco Martin
Browse files

Move WindowHeap delegate to own file

This makes easier for individual effects to personalize it
without adding ad-hoc api in the main WindowHeap class.
WindowHeap and WindowHEapDelegate are still quite coupled and thing can probably still be improved, but the code should be more readable already
parent d24df924
Pipeline #194821 passed with stage
in 42 minutes and 17 seconds
......@@ -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) {
......
......@@ -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
......@@ -188,8 +189,6 @@ FocusScope {
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 }
}
}
}
......
......@@ -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 {}
}
}
......
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
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
}
}
]
transitions: Transition {
to: "normal"
enabled: thumb.windowHeap.animationEnabled
NumberAnimation {
duration: thumb.windowHeap.animationDuration
properties: "x, y, width, height, opacity"
easing.type: Easing.OutCubic
}
}