diff --git a/containment/package/contents/ui/applet/AppletItem.qml b/containment/package/contents/ui/applet/AppletItem.qml index b7ce1fac..2c14f683 100644 --- a/containment/package/contents/ui/applet/AppletItem.qml +++ b/containment/package/contents/ui/applet/AppletItem.qml @@ -1,782 +1,782 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock 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 2 of * the License, or (at your option) any later version. * * Latte-Dock 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.1 import QtQuick.Layouts 1.1 import QtGraphicalEffects 1.0 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.kquickcontrolsaddons 2.0 import org.kde.latte 0.1 as Latte import "../../code/AppletIdentifier.js" as AppletIndetifier Item { id: container visible: false width: isInternalViewSplitter && !root.editMode ? 0 : (root.isHorizontal ? computeWidth : computeWidth + shownAppletMargin) height: isInternalViewSplitter && !root.editMode ? 0 : (root.isVertical ? computeHeight : computeHeight + shownAppletMargin) property bool animationsEnabled: true property bool animationWasSent: false //protection flag for animation broadcasting property bool canBeHovered: true property bool inFillCalculations: false //temp record, is used in calculations for fillWidth,fillHeight applets property bool needsFillSpace: { //fill flag, it is used in calculations for fillWidth,fillHeight applets if (!applet || !applet.Layout || (applet && applet.pluginName === "org.kde.plasma.panelspacer")) return false; if (((root.isHorizontal && applet.Layout.fillWidth===true) || (root.isVertical && applet.Layout.fillHeight===true)) && (applet.status !== PlasmaCore.Types.HiddenStatus)) return true; else return false; } property bool showZoomed: false property bool lockZoom: false property bool isExpanded: applet && applet.status >= PlasmaCore.Types.NeedsAttentionStatus && applet.status !== PlasmaCore.Types.HiddenStatus property bool isHidden: applet && applet.status === PlasmaCore.Types.HiddenStatus ? true : false property bool isInternalViewSplitter: (internalSplitterId > 0) property bool isZoomed: false property bool isSeparator: applet && applet.pluginName === "audoban.applet.separator" property bool firstChildOfStartLayout: (index === layoutsContainer.startLayout.beginIndex) property bool lastChildOfEndLayout: ((index === layoutsContainer.endLayout.beginIndex+layoutsContainer.endLayout.count-1)&&(layoutsContainer.endLayout.count>1)) //applet is in starting edge /*property bool startEdge: index < layoutsContainer.endLayout.beginIndex ? (index === 0)&&(layoutsContainer.mainLayout.count > 1) : (index === layoutsContainer.endLayout.beginIndex)&&(layoutsContainer.endLayout.count > 1)*/ property bool startEdge: (index === layoutsContainer.startLayout.beginIndex) || (index === layoutsContainer.mainLayout.beginIndex) || (index === layoutsContainer.endLayout.beginIndex) //applet is in ending edge property bool endEdge: plasmoid.configuration.panelPosition !== Latte.Dock.Justify ? (index === layoutsContainer.mainLayout.beginIndex + layoutsContainer.mainLayout.count - 1)&&(layoutsContainer.mainLayout.count>1) : (((index === layoutsContainer.startLayout.beginIndex+layoutsContainer.startLayout.count-2)&&(layoutsContainer.startLayout.count>2)) ||((index === layoutsContainer.mainLayout.beginIndex+layoutsContainer.mainLayout.count-2)&&(layoutsContainer.mainLayout.count>2)) ||((index === layoutsContainer.endLayout.beginIndex+layoutsContainer.endLayout.count-1)&&(layoutsContainer.endLayout.count>1))) property int animationTime: root.durationTime* (1.2 *units.shortDuration) // 70 property int hoveredIndex: layoutsContainer.hoveredIndex property int index: -1 property int appletMargin: (applet && (applet.pluginName === root.plasmoidName)) || isInternalViewSplitter || root.reverseLinesPosition ? 0 : root.statesLineSize property int maxWidth: root.isHorizontal ? root.height : root.width property int maxHeight: root.isHorizontal ? root.height : root.width property int shownAppletMargin: applet && (applet.pluginName === "org.kde.plasma.systemtray") ? 0 : appletMargin property int internalSplitterId: 0 property int previousIndex: -1 property int sizeForFill: -1 //it is used in calculations for fillWidth,fillHeight applets property int spacersMaxSize: Math.max(0,Math.ceil(0.5*root.iconSize) - root.iconMargin) property int status: applet ? applet.status : -1 property real animationStep: Math.min(3, root.iconSize / 8) property real computeWidth: root.isVertical ? wrapper.width : hiddenSpacerLeft.width+wrapper.width+hiddenSpacerRight.width property real computeHeight: root.isVertical ? hiddenSpacerLeft.height + wrapper.height + hiddenSpacerRight.height : wrapper.height property string title: isInternalViewSplitter ? "Now Dock Splitter" : "" property Item applet: null property Item latteApplet: applet && (applet.pluginName === root.plasmoidName) ? (applet.children[0] ? applet.children[0] : null) : null property Item latteSpacer: applet && (applet.pluginName === "org.kde.latte.spacer") ? (applet.children[0] ? applet.children[0] : null) : null property Item appletWrapper: applet && ((applet.pluginName === root.plasmoidName) || (applet.pluginName === "org.kde.plasma.systemtray")) ? wrapper : wrapper.wrapperContainer property Item appletIconItem; //first applet's IconItem, to be activated onExit signal property Item appletImageItem; property Item tooltipVisualParent: titleTooltipParent //this is used for folderView and icon widgets to fake their visual property bool fakeIconItem: applet && appletIconItem //(applet.pluginName === "org.kde.plasma.folder" || applet.pluginName === "org.kde.plasma.icon") property alias containsMouse: appletMouseArea.containsMouse property alias pressed: appletMouseArea.pressed /*onComputeHeightChanged: { if(index==0) console.log(computeHeight); }*/ //a timer that is used in order to init the fake applets on startup Timer { id: fakeInitTimer interval: 4000 onTriggered: AppletIndetifier.reconsiderAppletIconItem(); } //set up the fake containers and properties for when a fakeIconItem must be presented to the user //because the plasma widgets specific implementation breaks the Latte experience onFakeIconItemChanged: { if (fakeIconItem) { applet.opacity = 0; if (applet.pluginName === "org.kde.plasma.folder") { applet.parent = wrapper.fakeIconItemContainer; applet.anchors.fill = wrapper.fakeIconItemContainer; } wrapper.disableScaleWidth = false; wrapper.disableScaleHeight = false; wrapper.updateLayoutWidth(); wrapper.updateLayoutHeight(); } } /// BEGIN functions function checkIndex(){ index = -1; for(var i=0; i root.iconSize) && root.isHorizontal) || (applet && (applet.Layout.minimumHeight > root.iconSize) && root.isVertical)) && (applet && applet.pluginName !== "org.kde.plasma.panelspacer") && !container.fakeIconItem) || (applet && applet.pluginName === "org.kde.plasma.systemtray") || (container.needsFillSpace) ) { canBeHovered = false; } else{ canBeHovered = true; } } //! pos in global root positioning function containsPos(pos) { var relPos = root.mapToItem(container,pos.x, pos.y); if (relPos.x>=0 && relPos.x<=width && relPos.y>=0 && relPos.y<=height) return true; return false; } function reconsiderAppletIconItem() { AppletIndetifier.reconsiderAppletIconItem(); } ///END functions //BEGIN connections onAppletChanged: { if (!applet) { destroy(); } else { AppletIndetifier.reconsiderAppletIconItem(); fakeInitTimer.start(); } } onHoveredIndexChanged:{ if ( (Math.abs(hoveredIndex-index) > 1) && (hoveredIndex !== -1) ) { wrapper.zoomScale = 1; } if (Math.abs(hoveredIndex-index) >= 1) { hiddenSpacerLeft.nScale = 0; hiddenSpacerRight.nScale = 0; } } onIndexChanged: { if (container.latteApplet) { root.latteAppletPos = index; } if (isHidden) { parabolicManager.setHidden(previousIndex, index); } if (isSeparator) { parabolicManager.setSeparator(previousIndex, index); } if (index>-1) { previousIndex = index; } } onIsExpandedChanged: { if (isExpanded) { root.hideTooltipLabel(); } } onIsHiddenChanged: { if (isHidden) { parabolicManager.setHidden(-1, index); } else { parabolicManager.setHidden(index, -1); } } onIsSeparatorChanged: { if (isSeparator) { parabolicManager.setSeparator(-1, index); } else { parabolicManager.setSeparator(index, -1); } } onLatteAppletChanged: { if(container.latteApplet){ root.latteApplet = container.latteApplet; root.latteAppletContainer = container; root.latteAppletPos = index; latteApplet.latteDock = root; latteApplet.forceHidePanel = true; } } onLatteSpacerChanged: { if(container.latteSpacer){ latteSpacer.latteDock = root; container.lockZoom = true; } } onNeedsFillSpaceChanged: checkCanBeHovered(); onShowZoomedChanged: { if(showZoomed){ //var newZ = container.maxHeight / root.iconSize; //wrapper.zoomScale = newZ; wrapper.zoomScale = 1; } else{ wrapper.zoomScale = 1; } } Component.onCompleted: { checkIndex(); root.updateIndexes.connect(checkIndex); root.clearZoomSignal.connect(clearZoom); } Component.onDestruction: { if (isSeparator){ parabolicManager.setSeparator(previousIndex, -1); } if (isHidden) parabolicManager.setHidden(previousIndex, -1); root.updateIndexes.disconnect(checkIndex); root.clearZoomSignal.disconnect(clearZoom); } Connections{ target: root onLatteAppletHoveredIndexChanged: { if ( (root.zoomFactor>1) && (root.latteAppletHoveredIndex >= 0) ){ var distance = 2; //for Tasks plasmoid distance of 2 is not always safe there are //cases that needs to be 3, when an internal separator there is //between the hovered task and the current applet if (root.latteInternalSeparatorPos>=0) { if ((index < root.latteAppletPos && root.latteInternalSeparatorPos < root.latteAppletHoveredIndex) || (index > root.latteAppletPos && root.latteInternalSeparatorPos > root.latteAppletHoveredIndex)) { distance = 3; } } if(Math.abs(index-root.latteAppletPos+root.latteAppletHoveredIndex)>=distance) { container.clearZoom(); } } } } Connections{ target: layoutsContainer onHoveredIndexChanged:{ //for applets it is safe to consider that a distance of 2 //is enough to clearZoom if ( (root.zoomFactor>1) && (layoutsContainer.hoveredIndex>=0) && (Math.abs(index-layoutsContainer.hoveredIndex)>=2)) container.clearZoom(); } } ///END connections PlasmaComponents.BusyIndicator { z: 1000 visible: applet && applet.busy running: visible anchors.centerIn: parent width: Math.min(parent.width, parent.height) height: width } /* Rectangle{ anchors.fill: parent color: "transparent" border.color: "green" border.width: 1 }*/ Flow{ id: appletFlow width: container.computeWidth height: container.computeHeight anchors.rightMargin: (latteApplet || (showZoomed && root.editMode)) || (plasmoid.location !== PlasmaCore.Types.RightEdge) ? 0 : shownAppletMargin anchors.leftMargin: (latteApplet || (showZoomed && root.editMode)) || (plasmoid.location !== PlasmaCore.Types.LeftEdge) ? 0 : shownAppletMargin anchors.topMargin: (latteApplet || (showZoomed && root.editMode)) || (plasmoid.location !== PlasmaCore.Types.TopEdge)? 0 : shownAppletMargin anchors.bottomMargin: (latteApplet || (showZoomed && root.editMode)) || (plasmoid.location !== PlasmaCore.Types.BottomEdge) ? 0 : shownAppletMargin // a hidden spacer for the first element to add stability // IMPORTANT: hidden spacers must be tested on vertical !!! Item{ id: hiddenSpacerLeft //we add one missing pixel from calculations width: root.isHorizontal ? nHiddenSize : wrapper.width height: root.isHorizontal ? wrapper.height : nHiddenSize ///check also if this is the first plasmoid in anylayout visible: container.startEdge || separatorSpace>0 property bool neighbourSeparator: false; //in case there is a neighbour internal separator - property int separatorSpace: ((root.latteApplet && root.latteApplet.hasInternalSeparator + property int separatorSpace: ((root.latteApplet && root.latteApplet.hasInternalSeparator && !root.latteApplet.internalSeparatorHidden && (root.latteApplet.internalSeparatorPos === root.tasksCount-1) && index===root.latteAppletPos+1) || neighbourSeparator) && !container.isSeparator && !container.latteApplet ? (2+root.iconMargin/2) : 0 property real nHiddenSize: (nScale > 0) ? (container.spacersMaxSize * nScale) + separatorSpace : separatorSpace property real nScale: 0 Behavior on nScale { enabled: !root.globalDirectRender NumberAnimation { duration: 3*container.animationTime } } Behavior on nScale { enabled: root.globalDirectRender NumberAnimation { duration: root.directRenderAnimationTime } } Connections{ target: root onSeparatorsUpdated: { hiddenSpacerLeft.neighbourSeparator = parabolicManager.isSeparator(index-1); } } Loader{ width: !root.isVertical ? parent.width : 1 height: !root.isVertical ? 1 : parent.height x: root.isVertical ? parent.width /2 : 0 y: !root.isVertical ? parent.height /2 : 0 active: root.debugMode sourceComponent: Rectangle{ border.width: 1 border.color: "red" color: "transparent" } } } AppletItemWrapper{ id: wrapper TitleTooltipParent{ id: titleTooltipParent } } // a hidden spacer on the right for the last item to add stability Item{ id: hiddenSpacerRight //we add one missing pixel from calculations width: root.isHorizontal ? nHiddenSize : wrapper.width height: root.isHorizontal ? wrapper.height : nHiddenSize //check if this last plasmoid in any layout visible: container.endEdge || separatorSpace>0 property bool neighbourSeparator: false; //in case there is a neighbour internal separator - property int separatorSpace: ((root.latteApplet && root.latteApplet.hasInternalSeparator + property int separatorSpace: ((root.latteApplet && root.latteApplet.hasInternalSeparator && !root.latteApplet.internalSeparatorHidden && root.latteApplet.internalSeparatorPos === 0 && index===root.latteAppletPos-1) || neighbourSeparator) && !container.isSeparator && !container.latteApplet ? (2+root.iconMargin/2) : 0 property real nHiddenSize: (nScale > 0) ? (container.spacersMaxSize * nScale) + separatorSpace : separatorSpace property real nScale: 0 Behavior on nScale { enabled: !root.globalDirectRender NumberAnimation { duration: 3*container.animationTime } } Behavior on nScale { enabled: root.globalDirectRender NumberAnimation { duration: root.directRenderAnimationTime } } Connections{ target: root onSeparatorsUpdated: { hiddenSpacerRight.neighbourSeparator = parabolicManager.isSeparator(index+1); } } Loader{ width: !root.isVertical ? parent.width : 1 height: !root.isVertical ? 1 : parent.height x: root.isVertical ? parent.width /2 : 0 y: !root.isVertical ? parent.height /2 : 0 active: root.debugMode sourceComponent: Rectangle{ border.width: 1 border.color: "red" color: "transparent" } } } }// Flow with hidden spacers inside //! The Launchers Area Indicator Rectangle{ anchors.fill: parent radius: root.iconSize/10 property color tempColor: "#aa222222" color: tempColor border.width: 1 border.color: "#ff656565" opacity: latteApplet && root.addLaunchersMessage ? 1 : 0 Behavior on opacity{ NumberAnimation { duration: 2*root.durationTime*container.animationTime } } PlasmaExtras.Heading { width: parent.width height: parent.height text: i18n("Launchers Area") level: 3 font.bold: true horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap elide: Text.ElideRight rotation: { if (root.isHorizontal) return 0; else if (plasmoid.location === PlasmaCore.Types.LeftEdge) return -90; else if (plasmoid.location === PlasmaCore.Types.RightEdge) return 90; } } } MouseArea{ id: appletMouseArea anchors.fill: parent enabled: (!latteApplet)&&(canBeHovered)&&(!root.editMode)//&&(!lockZoom) hoverEnabled: !root.editMode && (!latteApplet) ? true : false propagateComposedEvents: true //! a way must be found in order for this be enabled //! only to support springloading for plasma 5.10 //! also on this is based the tooltips behavior by enabling it //! plasma tooltips are disabled visible: !container.latteApplet && !lockZoom && canBeHovered && !(container.isSeparator && !root.editMode) //&& (root.zoomFactor>1) property bool pressed: false onClicked: { pressed = false; mouse.accepted = false; } onEntered: { //AppletIndetifier.reconsiderAppletIconItem(); root.showTooltipLabel(container, applet.title); if (lockZoom || !canBeHovered) { return; } layoutsContainer.hoveredIndex = index; if (root.isHalfShown || (root.latteApplet && root.latteApplet.noTasksInAnimation>0)) { return; } if (root.isHorizontal){ layoutsContainer.currentSpot = mouseX; wrapper.calculateScales(mouseX); } else{ layoutsContainer.currentSpot = mouseY; wrapper.calculateScales(mouseY); } } onExited:{ if (appletIconItem && appletIconItem.visible) appletIconItem.active = false; root.hideTooltipLabel(); if (root.zoomFactor>1){ checkRestoreZoom.start(); } } onPositionChanged: { // if(!pressed){ if (lockZoom || !canBeHovered) { mouse.accepted = false; return; } if (root.isHalfShown || (root.latteApplet && root.latteApplet.noTasksInAnimation>0)) { return; } if( ((wrapper.zoomScale == 1 || wrapper.zoomScale === root.zoomFactor) && !root.globalDirectRender) || root.globalDirectRender) { if (root.isHorizontal){ var step = Math.abs(layoutsContainer.currentSpot-mouse.x); if (step >= container.animationStep){ layoutsContainer.hoveredIndex = index; layoutsContainer.currentSpot = mouse.x; wrapper.calculateScales(mouse.x); } } else{ var step = Math.abs(layoutsContainer.currentSpot-mouse.y); if (step >= container.animationStep){ layoutsContainer.hoveredIndex = index; layoutsContainer.currentSpot = mouse.y; wrapper.calculateScales(mouse.y); } } } mouse.accepted = false; } onPressed: { pressed = true; mouse.accepted = false; } onReleased: { pressed = false; } } //BEGIN states states: [ State { name: "left" when: (plasmoid.location === PlasmaCore.Types.LeftEdge) AnchorChanges { target: appletFlow anchors{ top:undefined; bottom:undefined; left:parent.left; right:undefined;} } }, State { name: "right" when: (plasmoid.location === PlasmaCore.Types.RightEdge) AnchorChanges { target: appletFlow anchors{ top:undefined; bottom:undefined; left:undefined; right:parent.right;} } }, State { name: "bottom" when: (plasmoid.location === PlasmaCore.Types.BottomEdge) AnchorChanges { target: appletFlow anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:undefined;} } }, State { name: "top" when: (plasmoid.location === PlasmaCore.Types.TopEdge) AnchorChanges { target: appletFlow anchors{ top:parent.top; bottom:undefined; left:undefined; right:undefined;} } } ] //END states //BEGIN animations ///////Restore Zoom Animation///// ParallelAnimation{ id: restoreAnimation PropertyAnimation { target: wrapper property: "zoomScale" to: 1 duration: 3 * container.animationTime easing.type: Easing.Linear } PropertyAnimation { target: hiddenSpacerLeft property: "nScale" to: 0 duration: 3 * container.animationTime easing.type: Easing.Linear } PropertyAnimation { target: hiddenSpacerRight property: "nScale" to: 0 duration: 3 * container.animationTime easing.type: Easing.Linear } } /////Clicked Animation///// SequentialAnimation{ id: clickedAnimation alwaysRunToEnd: true running: appletMouseArea.pressed && (root.durationTime > 0) onStopped: appletMouseArea.pressed = false; ParallelAnimation{ PropertyAnimation { target: wrapper.clickedEffect property: "brightness" to: -0.35 duration: units.longDuration easing.type: Easing.OutQuad } } ParallelAnimation{ PropertyAnimation { target: wrapper.clickedEffect property: "brightness" to: 0 duration: units.longDuration easing.type: Easing.OutQuad } } } //END animations } diff --git a/plasmoid/package/contents/ui/ParabolicManager.qml b/plasmoid/package/contents/ui/ParabolicManager.qml index 12f0cc03..12e4c179 100644 --- a/plasmoid/package/contents/ui/ParabolicManager.qml +++ b/plasmoid/package/contents/ui/ParabolicManager.qml @@ -1,213 +1,214 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock 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 2 of * the License, or (at your option) any later version. * * Latte-Dock 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.0 // holds all the logic around parabolic effect signals into one place. // ParabolicManager is responsible for triggering all the messages to tasks // that are neighbour to the hovered task. This will help a lot to catch cases // such as separators and proper clearing zoom. Item { id: parManager property bool hasInternalSeparator: false + property bool internalSeparatorHidden: (internalSeparatorPos === 0) || (internalSeparatorPos === root.tasksCount - 1) property int internalSeparatorPos: -1 onInternalSeparatorPosChanged: { if (internalSeparatorPos>-1) hasInternalSeparator = true; else hasInternalSeparator = false; } //!this is used in order to update the index when the signal is for applets //!outside the latte plasmoid function updateIdSendScale(index, zScale, zStep){ if ((index>=0 && index<=root.tasksCount-1) || (!root.latteDock)){ root.updateScale(index, zScale, zStep); return -1; } else{ var appletId = latteDock.latteAppletPos; if (index<0) appletId = latteDock.parabolicManager.availableLowerId(latteDock.latteAppletPos + index); else if (index>root.tasksCount-1){ var step=index-root.tasksCount+1; appletId = latteDock.parabolicManager.availableHigherId(latteDock.latteAppletPos + step); } latteDock.updateScale(appletId, zScale, zStep); return appletId; } } function applyParabolicEffect(index, currentMousePosition, center) { var rDistance = Math.abs(currentMousePosition - center); //check if the mouse goes right or down according to the center var positiveDirection = ((currentMousePosition - center) >= 0 ); var minimumZoom = 1; //finding the zoom center e.g. for zoom:1.7, calculates 0.35 var zoomCenter = ((root.zoomFactor + minimumZoom)/2) - 1; //computes the in the scale e.g. 0...0.35 according to the mouse distance //0.35 on the edge and 0 in the center var firstComputation = (rDistance / center) * (zoomCenter-minimumZoom+1); //calculates the scaling for the neighbour tasks var bigNeighbourZoom = Math.min(1 + zoomCenter + firstComputation, root.zoomFactor); var smallNeighbourZoom = Math.max(1 + zoomCenter - firstComputation, minimumZoom); //bigNeighbourZoom = Number(bigNeighbourZoom.toFixed(4)); //smallNeighbourZoom = Number(smallNeighbourZoom.toFixed(4)); var leftScale; var rightScale; if(positiveDirection === true){ rightScale = bigNeighbourZoom; leftScale = smallNeighbourZoom; } else { rightScale = smallNeighbourZoom; leftScale = bigNeighbourZoom; } // console.debug(leftScale + " " + rightScale + " " + index); //first applets accessed var gPAppletId = -1; var lPAppletId = -1; //secondary applets accessed to restore zoom var gAppletId = -1; var lAppletId = -1; var gStep = 1; var lStep = 1; if(!hasInternalSeparator || Math.abs(index-internalSeparatorPos)>=2){ //console.log("--- task style 1..."); gPAppletId = updateIdSendScale(index+1, rightScale, 0); lPAppletId = updateIdSendScale(index-1, leftScale, 0); //console.log("index:"+index + " lattePos:"+latteDock.latteAppletPos); //console.log("gApp:"+gPAppletId+" lApp:"+lPAppletId); if (latteDock) { if (gPAppletId > -1) gStep = Math.abs(gPAppletId - latteDock.latteAppletPos); else if (lPAppletId > -1) lStep = Math.abs(lPAppletId - latteDock.latteAppletPos); } //console.log("gs:"+gStep+" ls:"+lStep); gAppletId = updateIdSendScale(index+gStep+1, 1, 0); lAppletId = updateIdSendScale(index-lStep-1, 1, 0); //console.log(" cgApp:"+gAppletId+" clApp:"+lAppletId); clearTasksGreaterThan(index+1); clearTasksLowerThan(index-1); } else if(root.internalSeparatorPos>=0) { if(internalSeparatorPos === index+1){ //console.log("--- task style 2..."); gPAppletId = updateIdSendScale(index+2, rightScale, 0); lPAppletId = updateIdSendScale(index-1, leftScale, 0); //console.log("index:"+index + " lattePos:"+latteDock.latteAppletPos); //console.log("gApp:"+gPAppletId+" lApp:"+lPAppletId); if (latteDock) { gStep = 2; if (gPAppletId > -1) gStep = Math.abs(gPAppletId - latteDock.latteAppletPos); else if (lPAppletId > -1) lStep = Math.abs(lPAppletId - latteDock.latteAppletPos); } //console.log("gs:"+gStep+" ls:"+lStep); gAppletId = updateIdSendScale(index+gStep+2, 1, 0); lAppletId = updateIdSendScale(index-lStep-1, 1, 0); //console.log(" cgApp:"+gAppletId+" clApp:"+lAppletId); clearTasksGreaterThan(index+2); clearTasksLowerThan(index-1); } else if(internalSeparatorPos === index-1) { //console.log("--- task style 3..."); gPAppletId = updateIdSendScale(index+1, rightScale, 0); lPAppletId = updateIdSendScale(index-2, leftScale, 0); //console.log("index:"+index + " lattePos:"+latteDock.latteAppletPos); //console.log("gApp:"+gPAppletId+" lApp:"+lPAppletId); if (latteDock) { gStep = 1; lStep = 2; if (gPAppletId > -1) gStep = Math.abs(gPAppletId - latteDock.latteAppletPos); else if (lPAppletId > -1) lStep = Math.abs(lPAppletId - latteDock.latteAppletPos); } //console.log("gs:"+gStep+" ls:"+lStep); gAppletId = updateIdSendScale(index+gStep+1, 1, 0); lAppletId = updateIdSendScale(index-lStep-2, 1, 0); //console.log(" cgApp:"+gAppletId+" clApp:"+lAppletId); clearTasksGreaterThan(index+1); clearTasksLowerThan(index-2); } } if (latteDock){ if (gAppletId > -1) latteDock.parabolicManager.clearAppletsGreaterThan(gAppletId); else latteDock.parabolicManager.clearAppletsGreaterThan(latteDock.latteAppletPos); if (lAppletId > -1) latteDock.parabolicManager.clearAppletsLowerThan(lAppletId); else latteDock.parabolicManager.clearAppletsLowerThan(latteDock.latteAppletPos); } return {leftScale:leftScale, rightScale:rightScale}; } function clearTasksGreaterThan(index) { if (index0 && root.tasksCount>2) { for(var i=0; i * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock 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 2 of * the License, or (at your option) any later version. * * Latte-Dock 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.0 import QtQuick.Layouts 1.1 import QtGraphicalEffects 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.plasmoid 2.0 import org.kde.taskmanager 0.1 as TaskManager import org.kde.plasma.private.taskmanager 0.1 as TaskManagerApplet import org.kde.activities 0.1 as Activities import org.kde.latte 0.1 as Latte import "task" as Task import "../code/tools.js" as TaskTools import "../code/activitiesTools.js" as ActivitiesTools Item { id:root // Layout.fillHeight: userPanelPosition === 0 ? true : false // Layout.fillWidth: userPanelPosition === 0 ? true : false ///IMPORTANT: These values must be tested when the Now Dock Panel support ///also the four new anchors. A small issue is shown between the animation /// of the now dock plasmoid and the neighbour widgets... Layout.minimumWidth: (userPanelPosition !== 0)&&(!latteDock) ? clearWidth : -1 Layout.minimumHeight: (userPanelPosition !== 0)&&(!latteDock) ? clearHeight : -1 Layout.preferredWidth: (userPanelPosition !== 0)&&(!latteDock) ? tasksWidth : -1 Layout.preferredHeight: (userPanelPosition !== 0)&&(!latteDock) ? tasksHeight : -1 property bool debugLocation: false //it is used to check both the applet and the containment for direct render property bool globalDirectRender: latteDock ? latteDock.globalDirectRender : icList.directRender property bool directRenderTimerIsRunning: latteDock ? latteDock.directRenderTimerIsRunning : enableDirectRenderTimer.running property bool editMode: latteDock ? latteDock.editMode : plasmoid.userConfiguring property bool disableRestoreZoom: false //blocks restore animation in rightClick property bool dropNewLauncher: false readonly property bool hasInternalSeparator: parabolicManager.hasInternalSeparator + readonly property bool internalSeparatorHidden: parabolicManager.internalSeparatorHidden property bool initializationStep: false //true property bool initializatedBuffers: true // noInitCreatedBuffers >= tasksStarting ? true : false property bool isHovered: false property bool showBarLine: plasmoid.configuration.showBarLine property bool showTasksNumbers: false property bool useThemePanel: plasmoid.configuration.useThemePanel property bool taskInAnimation: noTasksInAnimation > 0 ? true : false property bool transparentPanel: plasmoid.configuration.transparentPanel property bool vertical: ((root.position === PlasmaCore.Types.LeftPositioned) || (root.position === PlasmaCore.Types.RightPositioned)) ? true : false property int clearWidth property int clearHeight readonly property int internalSeparatorPos: parabolicManager.internalSeparatorPos property int newLocationDebugUse: PlasmaCore.Types.BottomPositioned property int newDroppedPosition: -1 property int noInitCreatedBuffers: 0 property int noTasksInAnimation: 0 property int themePanelSize: plasmoid.configuration.panelSize property int position : PlasmaCore.Types.BottomPositioned property int tasksStarting: 0 property int realSize: iconSize + iconMargin ///Dont use Math.floor it adds one pixel in animations and creates glitches property int widthMargins: root.vertical ? thickMargin : iconMargin property int heightMargins: !root.vertical ? thickMargin : iconMargin property real textColorLuma: 0.2126*theme.textColor.r + 0.7152*theme.textColor.g + 0.0722*theme.textColor.b //a small badgers record (id,value) //in order to track badgers when there are changes //in launcher reference from libtaskmanager property variant badgers:[] property variant launchersOnActivities: [] property variant waitingLaunchers: [] //global plasmoid reference to the context menu property QtObject contextMenu: null property QtObject contextMenuComponent: Qt.createComponent("ContextMenu.qml"); property Item dragSource: null property Item parabolicManager: _parabolicManager property color minimizedDotColor: textColorLuma > 0.5 ? Qt.darker(theme.textColor, 1+ (1-textColorLuma)) : Qt.lighter(theme.textColor, 1+(1-textColorLuma)) //separator calculations based on audoban's design property int maxSeparatorLength: { if (root.vertical) return 5 + heightMargins; else return 5 + widthMargins; } property real missingSeparatorLength: { if (!root.isVertical) return ((iconSize + widthMargins) * zoomFactor) - maxSeparatorLength; else return ((iconSize + heightMargins) * zoomFactor) - maxSeparatorLength; } //! it is used to play the animation correct when the user removes a launcher property string launcherForRemoval: "" //BEGIN Latte Dock properties property bool enableShadows: latteDock ? latteDock.enableShadows > 0 : plasmoid.configuration.showShadows property bool forceHidePanel: false property bool disableLeftSpacer: false property bool disableRightSpacer: false property bool dockIsHidden: latteDock ? latteDock.dockIsHidden : false property bool highlightWindows: latteDock ? latteDock.highlightWindows: plasmoid.configuration.highlightWindows property bool indicateAudioStreams: latteDock ? latteDock.indicateAudioStreams : plasmoid.configuration.indicateAudioStreams property bool mouseWheelActions: latteDock ? latteDock.mouseWheelActions : true property bool reverseLinesPosition: latteDock ? latteDock.reverseLinesPosition : plasmoid.configuration.reverseLinesPosition property bool dotsOnActive: latteDock ? latteDock.dotsOnActive : plasmoid.configuration.dotsOnActive property bool showGlow: latteDock ? latteDock.showGlow : plasmoid.configuration.showGlow property bool showOnlyCurrentScreen: latteDock ? latteDock.showOnlyCurrentScreen : plasmoid.configuration.showOnlyCurrentScreen property bool showOnlyCurrentDesktop: latteDock ? latteDock.showOnlyCurrentDesktop : plasmoid.configuration.showOnlyCurrentDesktop property bool showOnlyCurrentActivity: latteDock ? latteDock.showOnlyCurrentActivity : plasmoid.configuration.showOnlyCurrentActivity property bool showPreviews: latteDock ? latteDock.showToolTips : plasmoid.configuration.showToolTips property bool showWindowActions: latteDock ? latteDock.showWindowActions : plasmoid.configuration.showWindowActions property bool smartLaunchersEnabled: latteDock ? latteDock.smartLaunchersEnabled : plasmoid.configuration.smartLaunchersEnabled property bool threeColorsWindows: latteDock ? latteDock.threeColorsWindows : plasmoid.configuration.threeColorsWindows property bool titleTooltips: latteDock ? latteDock.titleTooltips : false property int directRenderAnimationTime: latteDock ? latteDock.directRenderAnimationTime : 0 property int dockHoveredIndex : latteDock ? latteDock.hoveredIndex : -1 property int iconMargin: latteDock ? latteDock.iconMargin : 0.12*iconSize property int iconSize: latteDock ? latteDock.iconSize : Math.max(plasmoid.configuration.iconSize, 16) property int middleClickAction: latteDock ? latteDock.middleClickAction : plasmoid.configuration.middleClickAction property int modifier: latteDock ? latteDock.modifier : -1 property int modifierClickAction: latteDock ? latteDock.modifierClickAction : -1 property int modifierClick: latteDock ? latteDock.modifierClick : -1 property int modifierQt:{ if (modifier === Latte.Dock.Shift) return Qt.ShiftModifier; else if (modifier === Latte.Dock.Ctrl) return Qt.ControlModifier; else if (modifier === Latte.Dock.Alt) return Qt.AltModifier; else if (modifier === Latte.Dock.Meta) return Qt.MetaModifier; else return -1; } //decouple iconMargin which now is used only for length calculations with thickMargins //which are used for thickness calculations property int thickMarginBase: latteDock ? latteDock.thickMarginBase : Math.ceil(iconMargin/2) property int thickMarginHigh: latteDock ? latteDock.thickMarginHigh : Math.ceil(iconMargin/2) property int thickMargin: thickMarginBase + thickMarginHigh property int statesLineSize: latteDock ? latteDock.statesLineSize : Math.ceil( root.iconSize/13 ) property int tasksHeight: mouseHandler.height property int tasksWidth: mouseHandler.width property int userPanelPosition: latteDock ? latteDock.panelAlignment : plasmoid.configuration.plasmoidPosition property real durationTime: latteDock ? latteDock.durationTime : plasmoid.configuration.durationTime property real zoomFactor: latteDock ? latteDock.zoomFactor : ( 1 + (plasmoid.configuration.zoomLevel / 20) ) property int appShadowSize: latteDock ? latteDock.appShadowSize : Math.ceil(0.12*iconSize) property string appShadowColor: latteDock ? latteDock.appShadowColor : "#ff080808" property alias tasksCount: tasksModel.count property alias hoveredIndex: icList.hoveredIndex property QtObject currentLayout : latteDock && latteDock.universalLayoutManager && latteDock.universalLayoutManager.currentLayout ? latteDock.universalLayoutManager.currentLayout : null property Item latteDock: null //END Now Dock Panel properties Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation Plasmoid.backgroundHints: PlasmaCore.Types.NoBackground signal clearZoomSignal(); signal draggingFinished(); signal mouseWasEntered(int delegateIndex, bool value); signal presentWindows(variant winIds); signal requestLayout; signal signalActionsBlockHiding(int value); signal signalAnimationsNeedBothAxis(int value); signal signalAnimationsNeedLength(int value); signal signalAnimationsNeedThickness(int value); signal signalPreviewsShown(); //signal signalDraggingState(bool value); signal showPreviewForTasks(QtObject group); //trigger updating scaling of neighbour delegates of zoomed delegate signal updateScale(int delegateIndex, real newScale, real step) signal publishTasksGeometries(); signal waitingLauncherRemoved(string launch); signal windowsHovered(variant winIds, bool hovered) //onAnimationsChanged: console.log(animations); /* Rectangle{ anchors.fill: parent border.width: 1 border.color: "red" color: "white" } */ onLatteDockChanged: { if (latteDock) plasmoid.configuration.isInLatteDock = true; else plasmoid.configuration.isInLatteDock = false; } Connections { target: plasmoid onLocationChanged: { root.updatePosition(); iconGeometryTimer.start(); } } Connections { target: plasmoid.configuration // onLaunchersChanged: tasksModel.launcherList = plasmoid.configuration.launchers onGroupingAppIdBlacklistChanged: tasksModel.groupingAppIdBlacklist = plasmoid.configuration.groupingAppIdBlacklist; onGroupingLauncherUrlBlacklistChanged: tasksModel.groupingLauncherUrlBlacklist = plasmoid.configuration.groupingLauncherUrlBlacklist; } Connections{ target: latteDock onDockIsHiddenChanged:{ if (latteDock.dockIsHidden) { windowsPreviewDlg.hide(); } } } ///// PlasmaCore.ColorScope{ id: colorScopePalette } ///// function launchersDropped(urls){ mouseHandler.urlsDroppedOnArea(urls); } ///UPDATE function launcherExists(url) { return (ActivitiesTools.getIndex(url, tasksModel.launcherList)>=0); } function taskExists(url) { var tasks = icList.contentItem.children; for(var i=0; i= 0) { hasSep = true; break; } } if (!hasSep) parabolicManager.internalSeparatorPos = -1; } function updateLaunchersList(){ if (latteDock.universalSettings && (latteDock.launchersGroup === Latte.Dock.LayoutLaunchers || latteDock.launchersGroup === Latte.Dock.GlobalLaunchers)) { if (latteDock.launchersGroup === Latte.Dock.LayoutLaunchers) { tasksModel.launcherList = latteDock.universalLayoutManager.currentLayout.launchers; } else if (latteDock.launchersGroup === Latte.Dock.GlobalLaunchers) { tasksModel.launcherList = latteDock.universalSettings.launchers; } } else { tasksModel.launcherList = plasmoid.configuration.launchers59; } } onActivityChanged: { ActivitiesTools.currentActivity = String(activity); } onLauncherListChanged: { if (currentLayout) { if (latteDock && latteDock.universalLayoutManager && latteDock.universalLayoutManager.currentLayout && latteDock.universalSettings && (latteDock.launchersGroup === Latte.Dock.LayoutLaunchers || latteDock.launchersGroup === Latte.Dock.GlobalLaunchers)) { if (latteDock.launchersGroup === Latte.Dock.LayoutLaunchers) { latteDock.universalLayoutManager.currentLayout.launchers = launcherList; } else if (latteDock.launchersGroup === Latte.Dock.GlobalLaunchers) { latteDock.universalSettings.launchers = launcherList; } } else { plasmoid.configuration.launchers59 = launcherList; } checkSeparator(); } } onGroupingAppIdBlacklistChanged: { plasmoid.configuration.groupingAppIdBlacklist = groupingAppIdBlacklist; } onGroupingLauncherUrlBlacklistChanged: { plasmoid.configuration.groupingLauncherUrlBlacklist = groupingLauncherUrlBlacklist; } onAnyTaskDemandsAttentionChanged: { if (anyTaskDemandsAttention){ plasmoid.status = PlasmaCore.Types.RequiresAttentionStatus; attentionTimerComponent.createObject(root); } } Component.onCompleted: { ActivitiesTools.launchersOnActivities = root.launchersOnActivities ActivitiesTools.currentActivity = String(activityInfo.currentActivity); ActivitiesTools.plasmoid = plasmoid; //var loadedLaunchers = ActivitiesTools.restoreLaunchers(); ActivitiesTools.importLaunchersToNewArchitecture(); if (currentLayout && latteDock.universalSettings && (latteDock.launchersGroup === Latte.Dock.LayoutLaunchers || latteDock.launchersGroup === Latte.Dock.GlobalLaunchers)) { if (latteDock.launchersGroup === Latte.Dock.LayoutLaunchers) { launcherList = latteDock.universalLayoutManager.currentLayout.launchers; } else if (latteDock.launchersGroup === Latte.Dock.GlobalLaunchers) { launcherList = latteDock.universalSettings.launchers; } } else { launcherList = plasmoid.configuration.launchers59; } groupingAppIdBlacklist = plasmoid.configuration.groupingAppIdBlacklist; groupingLauncherUrlBlacklist = plasmoid.configuration.groupingLauncherUrlBlacklist; icList.model = tasksModel; tasksStarting = count; checkSeparator(); ///Plasma 5.9 enforce grouping at all cases if (Latte.WindowSystem.frameworksVersion >= 335104) { groupingWindowTasksThreshold = -1; } } } //! TaskManagerBackend required a groupDialog setting otherwise it crashes. This patch //! sets one just in order not to crash TaskManagerBackend PlasmaCore.Dialog { //ghost group Dialog to not crash TaskManagerBackend id: groupDialogGhost visible: false type: PlasmaCore.Dialog.PopupMenu flags: Qt.WindowStaysOnTopHint hideOnWindowDeactivate: true location: plasmoid.location } TaskManagerApplet.Backend { id: backend taskManagerItem: root toolTipItem: toolTipDelegate highlightWindows: root.highlightWindows onAddLauncher: { tasksModel.requestAddLauncher(url); } Component.onCompleted: { //! In Plasma 5.9 TaskManagerBackend required a groupDialog setting //! otherwise it crashes. //! frameworks 5.29.0 provide id 335104 //! work only after Plasma 5.9 and frameworks 5.29 //! + added a check for groupDialog also when it is present //! in plasma 5.8 (that was introduced after 5.8.5) if (Latte.WindowSystem.frameworksVersion >= 335104 || (groupDialog !== undefined)) { groupDialog = groupDialogGhost; } } } TaskManagerApplet.DragHelper { id: dragHelper dragIconSize: units.iconSizes.medium } TaskManager.VirtualDesktopInfo { id: virtualDesktopInfo } TaskManager.ActivityInfo { id: activityInfo } PlasmaCore.DataSource { id: mpris2Source engine: "mpris2" connectedSources: sources function sourceNameForLauncherUrl(launcherUrl, pid) { if (!launcherUrl || launcherUrl == "") { return ""; } // MPRIS spec explicitly mentions that "DesktopEntry" is with .desktop extension trimmed // Moreover, remove URL parameters, like wmClass (part after the question mark) var desktopFileName = launcherUrl.toString().split('/').pop().split('?')[0].replace(".desktop", "") for (var i = 0, length = connectedSources.length; i < length; ++i) { var source = connectedSources[i]; // we intend to connect directly, otherwise the multiplexer steals the connection away if (source === "@multiplex") { continue; } var sourceData = data[source]; if (sourceData && sourceData.DesktopEntry === desktopFileName && (pid === undefined || sourceData.InstancePid === pid)) { return source; } } return "" } function startOperation(source, op) { var service = serviceForSource(source) var operation = service.operationDescription(op) return service.startOperationCall(operation) } function goPrevious(source) { startOperation(source, "Previous"); } function goNext(source) { startOperation(source, "Next"); } function playPause(source) { startOperation(source, "PlayPause"); } function stop(source) { startOperation(source, "Stop"); } function raise(source) { startOperation(source, "Raise"); } function quit(source) { startOperation(source, "Quit"); } } Loader { id: pulseAudio source: "PulseAudio.qml" active: root.indicateAudioStreams } ParabolicManager{ id: _parabolicManager } /* IconsModel{ id: iconsmdl }*/ Component{ id: attentionTimerComponent Timer{ id: attentionTimer interval:8500 onTriggered: { plasmoid.status = PlasmaCore.Types.PassiveStatus; destroy(); } Component.onCompleted: { start(); } } } //Timer to check if the mouse is still inside the ListView //IMPORTANT ::: This timer should be used only when the Latte plasmoid //is not inside a Latte dock Timer{ id:checkListHovered repeat:false; interval: 120 property int normalInterval: Math.max(120, 2 * (root.durationTime * 1.2 * units.shortDuration) + 50) onTriggered: { if(root.latteDock) console.log("Plasmoid, checkListHoveredTimer was called, even though it shouldnt..."); if (!root.containsMouse()) { if (enableDirectRenderTimer.running) enableDirectRenderTimer.stop(); icList.directRender = false; if(root.latteDock) { root.latteDock.globalDirectRender = false; root.latteDock.clearZoom(); } root.clearZoom(); } interval = normalInterval; } function startNormal(){ interval = normalInterval; start(); } function startDuration( duration){ interval = duration; start(); } } //this timer adds a delay into enabling direct rendering... //it gives the time to neighbour tasks to complete their animation //during first hovering phase //IMPORTANT ::: This timer should be used only when the Latte plasmoid //is not inside a Latte dock Timer { id: enableDirectRenderTimer interval: 4 * root.durationTime * units.shortDuration onTriggered: { if(root.latteDock) console.log("Plasmoid, enableDirectRenderTimer was called, even though it shouldnt..."); if (waitingLaunchers.length > 0) restart(); else icList.directRender = true; } } ///Red Liner!!! show the upper needed limit for annimations Rectangle{ anchors.horizontalCenter: !root.vertical ? parent.horizontalCenter : undefined anchors.verticalCenter: root.vertical ? parent.verticalCenter : undefined width: root.vertical ? 1 : 2 * root.iconSize height: root.vertical ? 2 * root.iconSize : 1 color: "red" x: (root.position === PlasmaCore.Types.LeftPositioned) ? neededSpace : parent.width - neededSpace y: (root.position === PlasmaCore.Types.TopPositioned) ? neededSpace : parent.height - neededSpace visible: plasmoid.configuration.zoomHelper property int neededSpace: zoomFactor*(iconSize+iconMargin) + statesLineSize } Item{ id:barLine opacity: (tasksModel.count > 0) && root.initializatedBuffers ? 1 : 0 /* anchors.bottom: (root.position === PlasmaCore.Types.BottomPositioned) ? parent.bottom : undefined anchors.top: (root.position === PlasmaCore.Types.TopPositioned) ? parent.top : undefined anchors.left: (root.position === PlasmaCore.Types.LeftPositioned) ? parent.left : undefined anchors.right: (root.position === PlasmaCore.Types.RightPositioned) ? parent.right : undefined anchors.horizontalCenter: !parent.vertical ? parent.horizontalCenter : undefined anchors.verticalCenter: parent.vertical ? parent.verticalCenter : undefined */ width: ( icList.orientation === Qt.Horizontal ) ? icList.width + spacing : smallSize height: ( icList.orientation === Qt.Vertical ) ? icList.height + spacing : smallSize property int spacing: root.iconSize / 2 property int smallSize: Math.max(3.7*root.statesLineSize, 16) Behavior on opacity{ NumberAnimation { duration: root.durationTime*units.longDuration } } /// plasmoid's default panel BorderImage{ anchors.fill:parent source: "../images/panel-west.png" border { left:8; right:8; top:8; bottom:8 } opacity: (plasmoid.configuration.showBarLine && !plasmoid.configuration.useThemePanel && !root.forceHidePanel) ? 1 : 0 visible: (opacity == 0) ? false : true horizontalTileMode: BorderImage.Stretch verticalTileMode: BorderImage.Stretch Behavior on opacity{ NumberAnimation { duration: root.durationTime*units.longDuration } } } /// item which is used as anchors for the plasma's theme Item{ id:belower width: (root.position === PlasmaCore.Types.LeftPositioned) ? shadowsSvgItem.margins.left : shadowsSvgItem.margins.right height: (root.position === PlasmaCore.Types.BottomPositioned)? shadowsSvgItem.margins.bottom : shadowsSvgItem.margins.top anchors.top: (root.position === PlasmaCore.Types.BottomPositioned) ? parent.bottom : undefined anchors.bottom: (root.position === PlasmaCore.Types.TopPositioned) ? parent.top : undefined anchors.right: (root.position === PlasmaCore.Types.LeftPositioned) ? parent.left : undefined anchors.left: (root.position === PlasmaCore.Types.RightPositioned) ? parent.right : undefined } /// the current theme's panel PlasmaCore.FrameSvgItem{ id: shadowsSvgItem anchors.bottom: (root.position === PlasmaCore.Types.BottomPositioned) ? belower.bottom : undefined anchors.top: (root.position === PlasmaCore.Types.TopPositioned) ? belower.top : undefined anchors.left: (root.position === PlasmaCore.Types.LeftPositioned) ? belower.left : undefined anchors.right: (root.position === PlasmaCore.Types.RightPositioned) ? belower.right : undefined anchors.horizontalCenter: !root.vertical ? parent.horizontalCenter : undefined anchors.verticalCenter: root.vertical ? parent.verticalCenter : undefined width: root.vertical ? panelSize + margins.left + margins.right: parent.width height: root.vertical ? parent.height : panelSize + margins.top + margins.bottom imagePath: "translucent/widgets/panel-background" prefix:"shadow" opacity: (plasmoid.configuration.showBarLine && plasmoid.configuration.useThemePanel && !root.forceHidePanel) ? 1 : 0 visible: (opacity == 0) ? false : true property int panelSize: ((root.position === PlasmaCore.Types.BottomPositioned) || (root.position === PlasmaCore.Types.TopPositioned)) ? plasmoid.configuration.panelSize + belower.height: plasmoid.configuration.panelSize + belower.width Behavior on opacity{ NumberAnimation { duration: root.durationTime*units.longDuration } } PlasmaCore.FrameSvgItem{ anchors.margins: belower.width-1 anchors.fill:parent imagePath: plasmoid.configuration.transparentPanel ? "translucent/widgets/panel-background" : "widgets/panel-background" } } MouseHandler { id: mouseHandler anchors.bottom: (root.position === PlasmaCore.Types.BottomPositioned) ? icList.bottom : undefined anchors.top: (root.position === PlasmaCore.Types.TopPositioned) ? icList.top : undefined anchors.left: (root.position === PlasmaCore.Types.LeftPositioned) ? icList.left : undefined anchors.right: (root.position === PlasmaCore.Types.RightPositioned) ? icList.right : undefined anchors.horizontalCenter: !root.vertical ? icList.horizontalCenter : undefined anchors.verticalCenter: root.vertical ? icList.verticalCenter : undefined width: root.vertical ? maxSize : icList.width height: root.vertical ? icList.height : maxSize target: icList property int maxSize: ((root.hoveredIndex>=0 || dockHoveredIndex>=0 ) && !root.dragSource) ? root.statesLineSize + root.zoomFactor * (root.iconSize + root.thickMargin) : root.statesLineSize + root.iconSize + root.thickMargin function urlsDroppedOnArea(urls){ // If all dropped URLs point to application desktop files, we'll add a launcher for each of them. var createLaunchers = urls.every(function (item) { return backend.isApplication(item) }); if (createLaunchers) { urls.forEach(function (item) { addLauncher(item); }); return; } if (!hoveredItem) { return; } // DeclarativeMimeData urls is a QJsonArray but requestOpenUrls expects a proper QList. var urlsList = backend.jsonArrayToUrlList(urls); // Otherwise we'll just start a new instance of the application with the URLs as argument, // as you probably don't expect some of your files to open in the app and others to spawn launchers. tasksModel.requestOpenUrls(hoveredItem.modelIndex(), urlsList); } onUrlsDropped: { if (latteDock && latteDock.launchersGroup >= Latte.Dock.LayoutLaunchers) { latteDock.universalLayoutManager.launchersSignals.urlsDropped(latteDock.launchersGroup, urls); } else { urlsDroppedOnArea(urls); } } } ListView { id:icList boundsBehavior: Flickable.StopAtBounds property int currentSpot : -1000 property int hoveredIndex : -1 property int previousCount : 0 property int tasksCount: tasksModel.count property bool delayingRemoval: false property bool directRender: false // onTasksCountChanged: updateImplicits(); // property int count: children ? children.length : 0 /* anchors.bottom: (root.position === PlasmaCore.Types.BottomPositioned) ? parent.bottom : undefined anchors.top: (root.position === PlasmaCore.Types.TopPositioned) ? parent.top : undefined anchors.left: (root.position === PlasmaCore.Types.LeftPositioned) ? parent.left : undefined anchors.right: (root.position === PlasmaCore.Types.RightPositioned) ? parent.right : undefined anchors.horizontalCenter: !root.vertical ? parent.horizontalCenter : undefined anchors.verticalCenter: root.vertical ? parent.verticalCenter : undefined */ width: !root.vertical ? contentWidth : mouseHandler.maxSize height: root.vertical ? contentHeight : mouseHandler.maxSize orientation: Qt.Horizontal delegate: Task.TaskDelegate{} /* Rectangle{ anchors.fill: parent border.width: 1 border.color: "red" color: "transparent" } */ //the duration of this animation should be as small as possible //it fixes a small issue with the dragging an item to change it's //position, if the duration is too big there is a point in the //list that an item is going back and forth too fast //more of a trouble moveDisplaced: Transition { NumberAnimation { properties: "x,y"; duration: root.durationTime*units.longDuration; easing.type: Easing.Linear } } ///this transition can not be used with dragging !!!! I breaks ///the lists indexes !!!!! /* move: Transition { NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.Linear } } */ function childAtPos(x, y){ var tasks = icList.contentItem.children; for(var i=0; i=choords.x) && (x<=choords.x+task.width) && (y>=choords.y) && (y<=choords.y+task.height)){ return task; } } return null; } function childAtIndex(position) { var tasks = icList.contentItem.children; if (position < 0) return; for(var i=0; i=parabolicManager.internalSeparatorPos) ? index+1 : index; for(var i=0; i=parabolicManager.internalSeparatorPos) ? index+1 : index; for(var i=0; i=0 ? ident1.substring(n + 1) : identifier; for(var i=0; i= 0) { task.badgeIndicator = value === "" ? 0 : Number(value); var badge = getBadger(identifierF); if (badge) { badge.value = value; } else { badgers.push({id: identifierF, value: value}); } } } } function getLauncherList() { return plasmoid.configuration.launchers59; } //! BEGIN ::: external launchers signals in order to update the tasks model function extSignalAddLauncher(group, launcher) { if (group === latteDock.launchersGroup) { tasksModel.requestAddLauncher(launcher); } } function extSignalRemoveLauncher(group, launcher) { if (group === latteDock.launchersGroup) { root.launcherForRemoval = launcher; tasksModel.requestRemoveLauncher(launcher); } } function extSignalAddLauncherToActivity(group, launcher, activity) { if (group === latteDock.launchersGroup) { tasksModel.requestAddLauncherToActivity(launcher, activity); } } function extSignalRemoveLauncherFromActivity(group, launcher, activity) { if (group === latteDock.launchersGroup) { if (activity === tasksModel.activity) { root.launcherForRemoval = launcher; } tasksModel.requestRemoveLauncherFromActivity(launcher, activity); } } function extSignalUrlsDropped(group, urls) { if (group === latteDock.launchersGroup) { mouseHandler.urlsDroppedOnArea(urls); } } function extSignalMoveTask(group, from, to) { if (group === latteDock.launchersGroup) { tasksModel.move(from, to); } } //! END ::: external launchers signals in order to update the tasks model //! it is used to add the fake desktop file which represents //! the separator (fake launcher) function addSeparator(){ tasksModel.requestAddLauncher("file:///latte-separator.desktop"); } function removeSeparator(){ tasksModel.requestRemoveLauncher("file:///latte-separator.desktop"); } function setShowTasksNumbers(showNumbers){ root.showTasksNumbers = showNumbers; } function previewContainsMouse() { if(toolTipDelegate && toolTipDelegate.containsMouse && toolTipDelegate.parentTask) return true; else return false; } function containsMouse(){ //console.log("s1..."); if (disableRestoreZoom && (root.contextMenu || windowsPreviewDlg.visible)) { return; } else { disableRestoreZoom = false; } if (!previewContainsMouse()) windowsPreviewDlg.hide(4); //console.log("s3..."); var tasks = icList.contentItem.children; for(var i=0; i0) { url = url.substring( 0, url.indexOf("?iconData=" ) ); } tasksModel.requestAddLauncher(url); } function resetDragSource() { dragSource.z = 0; dragSource = null; } function startEnableDirectRenderTimer() { if (latteDock) { latteDock.setGlobalDirectRender(true); latteDock.startEnableDirectRenderTimer(); } else { enableDirectRenderTimer.start(); } } function startCheckRestoreZoomTimer() { if (latteDock) { latteDock.startCheckRestoreZoomTimer(); } else { checkListHovered.startNormal(); } } ///REMOVE /*function createContextMenu(task) { var menu = root.contextMenuComponent.createObject(task); menu.visualParent = task; menu.mpris2Source = mpris2Source; menu.activitiesCount = activityModelInstance.count; return menu; }*/ function createContextMenu(rootTask, modelIndex, args) { var initialArgs = args || {} initialArgs.visualParent = rootTask; initialArgs.modelIndex = modelIndex; initialArgs.mpris2Source = mpris2Source; initialArgs.backend = backend; root.contextMenu = root.contextMenuComponent.createObject(rootTask, initialArgs); return root.contextMenu; } Component.onCompleted: { updatePosition(); root.presentWindows.connect(backend.presentWindows); root.windowsHovered.connect(backend.windowsHovered); // mouseHandler.urlDropped.connect(backend.urlDropped); dragHelper.dropped.connect(resetDragSource); } //BEGIN states //user set Panel Positions // 0-Center, 1-Left, 2-Right, 3-Top, 4-Bottom states: [ ///Bottom Edge State { name: "bottomCenter" when: (root.position === PlasmaCore.Types.BottomPosition && userPanelPosition===Latte.Dock.Center) AnchorChanges { target: barLine anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:undefined; horizontalCenter:parent.horizontalCenter; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:undefined; horizontalCenter:parent.horizontalCenter; verticalCenter:undefined} } }, State { name: "bottomLeft" when: (root.position === PlasmaCore.Types.BottomPosition && userPanelPosition===Latte.Dock.Left) AnchorChanges { target: barLine anchors{ top:undefined; bottom:parent.bottom; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:undefined; bottom:parent.bottom; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } }, State { name: "bottomRight" when: (root.position === PlasmaCore.Types.BottomPosition && userPanelPosition===Latte.Dock.Right) AnchorChanges { target: barLine anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } }, ///Top Edge State { name: "topCenter" when: (root.position === PlasmaCore.Types.TopPosition && userPanelPosition===Latte.Dock.Center) AnchorChanges { target: barLine anchors{ top:parent.top; bottom:undefined; left:undefined; right:undefined; horizontalCenter:parent.horizontalCenter; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:parent.top; bottom:undefined; left:undefined; right:undefined; horizontalCenter:parent.horizontalCenter; verticalCenter:undefined} } }, State { name: "topLeft" when: (root.position === PlasmaCore.Types.TopPosition && userPanelPosition===Latte.Dock.Left) AnchorChanges { target: barLine anchors{ top:parent.top; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:parent.top; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } }, State { name: "topRight" when: (root.position === PlasmaCore.Types.TopPosition && userPanelPosition===Latte.Dock.Right) AnchorChanges { target: barLine anchors{ top:parent.top; bottom:undefined; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:parent.top; bottom:undefined; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } }, ////Left Edge State { name: "leftCenter" when: (root.position === PlasmaCore.Types.LeftPosition && userPanelPosition===Latte.Dock.Center) AnchorChanges { target: barLine anchors{ top:undefined; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:parent.verticalCenter} } AnchorChanges { target: icList anchors{ top:undefined; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:parent.verticalCenter} } }, State { name: "leftTop" when: (root.position === PlasmaCore.Types.LeftPosition && userPanelPosition===Latte.Dock.Top) AnchorChanges { target: barLine anchors{ top:parent.top; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:parent.top; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } }, State { name: "leftBottom" when: (root.position === PlasmaCore.Types.LeftPosition && userPanelPosition===Latte.Dock.Bottom) AnchorChanges { target: barLine anchors{ top:undefined; bottom:parent.bottom; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:undefined; bottom:parent.bottom; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } }, ///Right Edge State { name: "rightCenter" when: (root.position === PlasmaCore.Types.RightPosition && userPanelPosition===Latte.Dock.Center) AnchorChanges { target: barLine anchors{ top:undefined; bottom:undefined; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:parent.verticalCenter} } AnchorChanges { target: icList anchors{ top:undefined; bottom:undefined; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:parent.verticalCenter} } }, State { name: "rightTop" when: (root.position === PlasmaCore.Types.RightPosition && userPanelPosition===Latte.Dock.Top) AnchorChanges { target: barLine anchors{ top:parent.top; bottom:undefined; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:parent.top; bottom:undefined; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } }, State { name: "rightBottom" when: (root.position === PlasmaCore.Types.RightPosition && userPanelPosition===Latte.Dock.Bottom) AnchorChanges { target: barLine anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } } ] //END states } diff --git a/plasmoid/package/contents/ui/task/TaskDelegate.qml b/plasmoid/package/contents/ui/task/TaskDelegate.qml index 4585fe2c..d025b8f5 100644 --- a/plasmoid/package/contents/ui/task/TaskDelegate.qml +++ b/plasmoid/package/contents/ui/task/TaskDelegate.qml @@ -1,1369 +1,1381 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock 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 2 of * the License, or (at your option) any later version. * * Latte-Dock 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.0 import QtQuick.Layouts 1.1 import QtGraphicalEffects 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.private.taskmanager 0.1 as TaskManagerApplet import org.kde.latte 0.1 as Latte import "animations" as TaskAnimations MouseArea{ id: mainItemContainer visible: false //true//(isStartup && root.durationTime !== 0) ? false : true anchors.bottom: (root.position === PlasmaCore.Types.BottomPositioned) ? parent.bottom : undefined anchors.top: (root.position === PlasmaCore.Types.TopPositioned) ? parent.top : undefined anchors.left: (root.position === PlasmaCore.Types.LeftPositioned) ? parent.left : undefined anchors.right: (root.position === PlasmaCore.Types.RightPositioned) ? parent.right : undefined objectName: "TaskDelegate" width: { if (!visible) return 0; if (isSeparator) return root.vertical ? separatorItem.width : (root.dragSource ? 5+root.iconMargin : 0); if (root.vertical) return wrapper.width; else return hiddenSpacerLeft.width+wrapper.width+hiddenSpacerRight.width; } height: { if (!visible) return 0; if (isSeparator) return !root.vertical ? separatorItem.height : (root.dragSource ? 5+root.iconMargin: 0); if (root.vertical) return hiddenSpacerLeft.height + wrapper.height + hiddenSpacerRight.height; else wrapper.height; } acceptedButtons: Qt.LeftButton | Qt.MidButton | Qt.RightButton hoverEnabled: visible && (inAnimation !== true) && (!IsStartup) && (!root.taskInAnimation) && (!root.editMode || root.debugLocation)&&(!inBouncingAnimation) && !isSeparator // hoverEnabled: false //opacity : isSeparator && (hiddenSpacerLeft.neighbourSeparator || hiddenSpacerRight.neighbourSeparator) ? 0 : 1 property bool buffersAreReady: false property bool delayingRemove: ListView.delayRemove //states that exist in windows in a Group of windows property bool hasActive: isActive property bool hasMinimized: (IsGroupParent === true) ? tasksWindows.hasMinimized : isMinimized property bool hasShown: (IsGroupParent === true) ? tasksWindows.hasShown : !isMinimized property bool inAddRemoveAnimation: true property bool inAnimation: true property bool inBlockingAnimation: false property bool inBouncingAnimation: false property bool inPopup: false property bool inRemoveStage: false property bool inWheelAction: false property bool isActive: (IsActive === true) ? true : false property bool isDemandingAttention: (IsDemandingAttention === true) ? true : false property bool isDragged: false property bool isGroupParent: (IsGroupParent === true) ? true : false property bool isLauncher: (IsLauncher === true) ? true : false property bool isMinimized: (IsMinimized === true) ? true : false property bool isSeparator: false property bool isStartup: (IsStartup === true) ? true : false property bool isWindow: (IsWindow === true) ? true : false property bool isZoomed: false property bool mouseEntered: false property bool pressed: false property int animationTime: root.durationTime * 1.2 * units.shortDuration property int badgeIndicator: 0 //it is used from external apps property int hoveredIndex: icList.hoveredIndex property int itemIndex: index property int lastValidIndex: -1 //used for the removal animation property int lastButtonClicked: -1; property int pressX: -1 property int pressY: -1 property int resistanceDelay: 450 property int spacersMaxSize: Math.max(0,Math.ceil(0.55*root.iconSize) - root.iconMargin) property real animationStep: Math.min(3, root.iconSize / 8) property string activity: tasksModel.activity readonly property var m: model readonly property int pid: model && model.AppPid ? model.AppPid : -1 readonly property string appName: model && model.AppName ? model.AppName : "" property string modelLauncherUrl: (LauncherUrlWithoutIcon !== null) ? LauncherUrlWithoutIcon : "" property string modelLauncherUrlWithIcon: (LauncherUrl !== null) ? LauncherUrl : "" property string launcherUrl: "" property string launcherUrlWithIcon: "" property Item tooltipVisualParent: wrapper.titleTooltipVisualParent onModelLauncherUrlChanged: { if (modelLauncherUrl !== "") launcherUrl = modelLauncherUrl; if (modelLauncherUrl.indexOf("latte-separator.desktop")>=0){ isSeparator = true; parabolicManager.internalSeparatorPos = index; } else { isSeparator = false; } } onModelLauncherUrlWithIconChanged: { if (modelLauncherUrlWithIcon !== ""){ launcherUrlWithIcon = modelLauncherUrlWithIcon; } } ////// Audio streams ////// property Item audioStreamOverlay property var audioStreams: [] readonly property bool hasAudioStream: root.indicateAudioStreams && audioStreams.length > 0 && !isLauncher readonly property bool playingAudio: hasAudioStream && audioStreams.some(function (item) { return !item.corked }) readonly property bool muted: hasAudioStream && audioStreams.every(function (item) { return item.muted }) readonly property int volume: { if (!hasAudioStream){ return 0; } var maxVolume = 0; for (var i=0; i maxVolume) maxVolume = audioStreams[i].volume; } return maxVolume; } ////// property QtObject contextMenu: null property QtObject draggingResistaner: null property QtObject hoveredTimerObj: null signal groupWindowAdded(); signal groupWindowRemoved(); signal checkWindowsStates(); Behavior on opacity { // NumberAnimation { duration: (IsStartup || (IsLauncher) ) ? 0 : 400 } NumberAnimation { duration: root.durationTime*units.longDuration } } TaskWindows{ id: tasksWindows property int previousCount: 0 onWindowsCountChanged: { if ((windowsCount >= 2) && (windowsCount > previousCount)){ if(root.dragSource == null) mainItemContainer.groupWindowAdded(); } else if ((windowsCount >=1) &&(windowsCount < previousCount)){ //sometimes this is triggered in dragging with no reason if(root.dragSource == null && !mainItemContainer.delayingRemove) mainItemContainer.groupWindowRemoved(); } if (windowsCount>=1) { mainItemContainer.slotPublishGeometries(); } previousCount = windowsCount; } } Item{ id:separatorItem anchors.rightMargin: root.position === PlasmaCore.Types.RightPositioned ? localThickMargin : 0 anchors.leftMargin: root.position === PlasmaCore.Types.LeftPositioned ? localThickMargin : 0 anchors.bottomMargin: root.position === PlasmaCore.Types.BottomPositioned ? localThickMargin : 0 anchors.topMargin: root.position === PlasmaCore.Types.TopPositioned ? localThickMargin : 0 anchors.horizontalCenter: !root.vertical ? parent.horizontalCenter : undefined anchors.verticalCenter: root.vertical ? parent.verticalCenter : undefined anchors.right: root.position === PlasmaCore.Types.RightPositioned ? parent.right : undefined; anchors.left: root.position === PlasmaCore.Types.LeftPositioned ? parent.left : undefined; anchors.top: root.position === PlasmaCore.Types.TopPositioned ? parent.top : undefined; anchors.bottom: root.position === PlasmaCore.Types.BottomPositioned ? parent.bottom : undefined; - opacity: separatorShadow.active ? 0 : 0.4 + opacity: separatorShadow.active || root.internalSeparatorHidden ? 0 : 0.4 visible: mainItemContainer.isSeparator width: root.vertical ? root.iconSize : (root.dragSource) ? 5+root.iconMargin: 1 height: !root.vertical ? root.iconSize : (root.dragSource) ? 5+root.iconMargin: 1 property int localThickMargin: root.statesLineSize + root.thickMarginBase + 4 + Behavior on opacity { + NumberAnimation { duration: root.durationTime*units.longDuration } + } + Rectangle { anchors.horizontalCenter: !root.vertical ? parent.horizontalCenter : undefined anchors.verticalCenter: root.vertical ? parent.verticalCenter : undefined anchors.right: root.position === PlasmaCore.Types.RightPositioned ? parent.right : undefined; anchors.left: root.position === PlasmaCore.Types.LeftPositioned ? parent.left : undefined; anchors.top: root.position === PlasmaCore.Types.TopPositioned ? parent.top : undefined; anchors.bottom: root.position === PlasmaCore.Types.BottomPositioned ? parent.bottom : undefined; radius: 2 width: root.vertical ? root.iconSize - 8 : 1 height: !root.vertical ? root.iconSize - 8 : 1 color: theme.textColor } } ///Shadow in tasks Loader{ id: separatorShadow anchors.fill: separatorItem active: root.enableShadows && isSeparator - opacity: 0.4 + opacity: root.internalSeparatorHidden ? 0 : 0.4 + + Behavior on opacity { + NumberAnimation { duration: root.durationTime*units.longDuration } + } sourceComponent: DropShadow{ anchors.fill: parent color: root.appShadowColor samples: 2 * radius source: separatorItem radius: root.appShadowSize verticalOffset: 2 } } /* Rectangle{ anchors.fill: parent color: "transparent" border.width: 1 border.color: "blue" } */ Flow{ id: taskFlow width: parent.width height: parent.height // a hidden spacer for the first element to add stability // IMPORTANT: hidden spacers must be tested on vertical !!! Item{ id: hiddenSpacerLeft //we add one missing pixel from calculations width: root.vertical ? wrapper.width : nHiddenSize height: root.vertical ? nHiddenSize : wrapper.height visible: (index === 0) || (separatorSpace > 0) property bool neighbourSeparator: false //in case there is a neighbour separator, lastValidIndex is used in order to protect from false //when the task is removed property int indexUsed: index === -1 ? lastValidIndex : index - property int separatorSpace: ((parabolicManager.internalSeparatorPos !== -1 && parabolicManager.internalSeparatorPos === indexUsed-1) + property int separatorSpace: ((parabolicManager.internalSeparatorPos !== -1 + && !root.internalSeparatorHidden + && parabolicManager.internalSeparatorPos === indexUsed-1) || neighbourSeparator) && !isSeparator && !showWindowAnimation.running ? (2+root.iconMargin/2) : 0 property real nHiddenSize: (nScale > 0) ? (mainItemContainer.spacersMaxSize * nScale) + separatorSpace : separatorSpace property real nScale: 0 function updateNeighbour() { //index===-1 indicates that this item is removed if (latteDock && index!==-1) { hiddenSpacerLeft.neighbourSeparator = latteDock.parabolicManager.isSeparator(latteDock.latteAppletPos-1) && indexUsed===0; } } Connections{ target: root onLatteDockChanged: hiddenSpacerLeft.updateNeighbour(); } Connections{ target: latteDock onSeparatorsUpdated: hiddenSpacerLeft.updateNeighbour(); onLatteAppletPosChanged: hiddenSpacerLeft.updateNeighbour(); } Connections{ target: mainItemContainer onItemIndexChanged: hiddenSpacerLeft.updateNeighbour(); } Component.onCompleted: hiddenSpacerLeft.updateNeighbour(); Behavior on nScale { enabled: !root.globalDirectRender NumberAnimation { duration: 3 * mainItemContainer.animationTime } } Behavior on nScale { enabled: root.globalDirectRender NumberAnimation { duration: root.directRenderAnimationTime } } Behavior on separatorSpace { enabled: wrapper.opacity > 0 NumberAnimation { duration: 3 * mainItemContainer.animationTime } } /* Rectangle{ width: !root.vertical ? parent.width : 1 height: !root.vertical ? 1 : parent.height x: root.vertical ? parent.width /2 : 0 y: !root.vertical ? parent.height /2 : 0 border.width: 1 border.color: "red" color: "transparent" }*/ } TaskWrapper{ id: wrapper } // a hidden spacer on the right for the last item to add stability Item{ id: hiddenSpacerRight //we add one missing pixel from calculations width: root.vertical ? wrapper.width : nHiddenSize height: root.vertical ? nHiddenSize : wrapper.height visible: (index === icList.count - 1) || (separatorSpace > 0) property bool neighbourSeparator: false //in case there is a neighbour separator, lastValidIndex is used in order to protect from false //when the task is removed property int indexUsed: index === -1 ? lastValidIndex : index - property int separatorSpace: ((parabolicManager.internalSeparatorPos !== -1 && parabolicManager.internalSeparatorPos === indexUsed+1) + property int separatorSpace: ((parabolicManager.internalSeparatorPos !== -1 + && !root.internalSeparatorHidden + && parabolicManager.internalSeparatorPos === indexUsed+1) || neighbourSeparator) && !isSeparator && !showWindowAnimation.running ? (2+root.iconMargin/2) : 0 property real nHiddenSize: (nScale > 0) ? (mainItemContainer.spacersMaxSize * nScale) + separatorSpace : separatorSpace property real nScale: 0 function updateNeighbour() { //index===-1 indicates that this item is removed if (latteDock && index!==-1) { hiddenSpacerRight.neighbourSeparator = latteDock.parabolicManager.isSeparator(latteDock.latteAppletPos+1) && indexUsed===root.tasksCount-1; } } Connections{ target: root onLatteDockChanged: hiddenSpacerRight.updateNeighbour(); } Connections{ target: latteDock onSeparatorsUpdated: hiddenSpacerRight.updateNeighbour(); onLatteAppletPosChanged: hiddenSpacerRight.updateNeighbour(); } Connections{ target: mainItemContainer onItemIndexChanged: hiddenSpacerRight.updateNeighbour(); } Component.onCompleted: hiddenSpacerRight.updateNeighbour(); Behavior on nScale { enabled: !root.globalDirectRender NumberAnimation { duration: 3 * mainItemContainer.animationTime } } Behavior on nScale { enabled: root.globalDirectRender NumberAnimation { duration: root.directRenderAnimationTime } } Behavior on separatorSpace { enabled: wrapper.opacity > 0 NumberAnimation { duration: 3 * mainItemContainer.animationTime } } /* Rectangle{ width: !root.vertical ? parent.width : 1 height: !root.vertical ? 1 : parent.height x: root.vertical ? parent.width /2 : 0 y: !root.vertical ? parent.height /2 : 0 border.width: 1 border.color: "red" color: "transparent" }*/ } }// Flow with hidden spacers inside /*Rectangle{ anchors.fill: taskFlow color: "transparent" border.width: 1 border.color: "blue" }*/ Component { id: taskInitComponent Timer { id: timer interval: 800 repeat: false onTriggered: { // mainItemContainer.hoverEnabled = true; slotPublishGeometries(); timer.destroy(); } Component.onCompleted: timer.start() } } ////// Values Changes ///// //restore scales when there is no zoom factor for that item or //the mouse is out of the ListView // onItemIndexChanged: { // } onAppNameChanged: updateAudioStreams() onPidChanged: updateAudioStreams() onHasAudioStreamChanged: updateAudioStreams() onHoveredIndexChanged: { var distanceFromHovered = Math.abs(index - icList.hoveredIndex); /*if( (distanceFromHovered > 1) && (hoveredIndex !== -1)){ if(!isDragged) wrapper.mScale = 1; }*/ if (distanceFromHovered >= 1) { hiddenSpacerLeft.nScale = 0; hiddenSpacerRight.nScale = 0; } } onItemIndexChanged: { if (itemIndex>=0) lastValidTimer.start(); if (isSeparator){ parabolicManager.internalSeparatorPos = itemIndex; } } onIsDraggedChanged: { if(isDragged && (!root.editMode)){ root.dragSource = mainItemContainer; dragHelper.startDrag(mainItemContainer, model.MimeType, model.MimeData, model.LauncherUrlWithoutIcon, model.decoration); pressX = -1; pressY = -1; } } onIsWindowChanged: { if (isWindow) { taskInitComponent.createObject(mainItemContainer); } } onIsMinimizedChanged: { checkWindowsStates(); } onIsActiveChanged: { checkWindowsStates(); } onLauncherUrlChanged: { var badger = root.getBadger(launcherUrl); if (badger && !isLauncher) { badgeIndicator = parseInt(badger.value); } else { badgeIndicator = 0; } } ////// End of Values Changes ///// ///////////////// Mouse Area Events /////////////////// onEntered: { if (root.editMode) return; if ((icList.hoveredIndex !== itemIndex) && isLauncher && windowsPreviewDlg.visible) { windowsPreviewDlg.hide(1); } if(!root.latteDock) checkListHovered.stop(); if (root.latteDock && root.latteDock.isHalfShown) { return; } if (root.latteDock && (!root.showPreviews || (root.showPreviews && isLauncher))){ root.latteDock.showTooltipLabel(mainItemContainer, model.AppName); } if((!inAnimation)&&(root.dragSource == null)&&(!root.taskInAnimation) && hoverEnabled){ icList.hoveredIndex = index; if (!inBlockingAnimation) { mouseEntered = true; root.mouseWasEntered(index-2, false); root.mouseWasEntered(index+2, false); root.mouseWasEntered(index-1, true); root.mouseWasEntered(index+1, true); if (icList.orientation == Qt.Horizontal){ icList.currentSpot = mouseX; wrapper.calculateScales(mouseX); } else{ icList.currentSpot = mouseY; wrapper.calculateScales(mouseY); } } } } // IMPORTANT: This must be improved ! even for small miliseconds it reduces performance onExited: { mouseEntered = false; if (root.latteDock && (!root.showPreviews || (root.showPreviews && isLauncher))){ root.latteDock.hideTooltipLabel(); } if(mainItemContainer.contextMenu && mainItemContainer.contextMenu.status == PlasmaComponents.DialogStatus.Open){ ///dont check to restore zooms } else{ if(!inAnimation){ root.startCheckRestoreZoomTimer(); } } /* if(draggingResistaner != null){ draggingResistaner.destroy(); draggingResistaner = null; isDragged = false; }*/ } onPositionChanged: { if (root.editMode || inBlockingAnimation) return; if(!root.latteDock) checkListHovered.stop(); if (root.latteDock && root.latteDock.isHalfShown) { return; } if((inAnimation == false)&&(!root.taskInAnimation)&&(!root.disableRestoreZoom) && hoverEnabled){ if( ((wrapper.mScale == 1 || wrapper.mScale === root.zoomFactor) && !root.globalDirectRender) || root.globalDirectRender) { if(root.dragSource == null){ if (icList.orientation == Qt.Horizontal){ var step = Math.abs(icList.currentSpot-mouse.x); if (step >= animationStep){ icList.hoveredIndex = index; icList.currentSpot = mouse.x; wrapper.calculateScales(mouse.x); } } else{ var step = Math.abs(icList.currentSpot-mouse.y); if (step >= animationStep){ icList.hoveredIndex = index; icList.currentSpot = mouse.y; wrapper.calculateScales(mouse.y); } } } } // mouse.button is always 0 here, hence checking with mouse.buttons if (pressX != -1 && mouse.buttons == Qt.LeftButton && isDragged && !root.editMode && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y) ) { root.dragSource = mainItemContainer; dragHelper.startDrag(mainItemContainer, model.MimeType, model.MimeData, model.LauncherUrlWithoutIcon, model.decoration); pressX = -1; pressY = -1; } else{ /* if(draggingResistaner != null){ draggingResistaner.destroy(); draggingResistaner = null; } isDragged = false;*/ } } } onContainsMouseChanged:{ if(!containsMouse){ // hiddenSpacerLeft.nScale = 0; // hiddenSpacerRight.nScale = 0; if(!inAnimation) pressed=false; } ////window previews///////// if (isWindow) { if(containsMouse && (root.showPreviews || (!root.showPreviews && root.highlightWindows)) && Latte.WindowSystem.compositingActive){ hoveredTimerObj = hoveredTimerComponent.createObject(mainItemContainer); } else{ if (hoveredTimerObj){ hoveredTimerObj.stop(); hoveredTimerObj.destroy(); } } } ////disable hover effect/// if (isWindow && root.highlightWindows && !containsMouse) { root.windowsHovered(model.LegacyWinIdList, false); } } onPressed: { //console.log("Pressed Task Delegate.."); if (Latte.WindowSystem.compositingActive) { windowsPreviewDlg.hide(2); } var modAccepted = modifierAccepted(mouse); if ((mouse.button == Qt.LeftButton)||(mouse.button == Qt.MidButton) || modAccepted) { lastButtonClicked = mouse.button; pressed = true; pressX = mouse.x; pressY = mouse.y; if(draggingResistaner == null && !modAccepted) draggingResistaner = resistanerTimerComponent.createObject(mainItemContainer); } else if (mouse.button == Qt.RightButton && !modAccepted){ // When we're a launcher, there's no window controls, so we can show all // places without the menu getting super huge. if (model.IsLauncher === true) { showContextMenu({showAllPlaces: true}) } else { showContextMenu(); } //root.createContextMenu(mainItemContainer).show(); } if (hoveredTimerObj){ hoveredTimerObj.restart(); /*hoveredTimerObj.stop(); hoveredTimerObj.destroy();*/ } } onReleased: { //console.log("Released Task Delegate..."); if (draggingResistaner != null){ draggingResistaner.destroy(); draggingResistaner = null; } if(pressed && !inBlockingAnimation && !isSeparator){ if (modifierAccepted(mouse)){ if( !mainItemContainer.isLauncher){ if (root.modifierClickAction == Latte.Dock.NewInstance) { tasksModel.requestNewInstance(modelIndex()); } else if (root.modifierClickAction == Latte.Dock.Close) { tasksModel.requestClose(modelIndex()); } else if (root.modifierClickAction == Latte.Dock.ToggleMinimized) { tasksModel.requestToggleMinimized(modelIndex()); } else if ( root.modifierClickAction == Latte.Dock.CycleThroughTasks) { if (isGroupParent) tasksWindows.activateNextTask(); else activateTask(); } else if (root.modifierClickAction == Latte.Dock.ToggleGrouping) { tasksModel.requestToggleGrouping(modelIndex()); } } else { activateTask(); } } else if (mouse.button == Qt.MidButton){ if( !mainItemContainer.isLauncher){ if (root.middleClickAction == Latte.Dock.NewInstance) { tasksModel.requestNewInstance(modelIndex()); } else if (root.middleClickAction == Latte.Dock.Close) { tasksModel.requestClose(modelIndex()); } else if (root.middleClickAction == Latte.Dock.ToggleMinimized) { tasksModel.requestToggleMinimized(modelIndex()); } else if ( root.middleClickAction == Latte.Dock.CycleThroughTasks) { if (isGroupParent) tasksWindows.activateNextTask(); else activateTask(); } else if (root.middleClickAction == Latte.Dock.ToggleGrouping) { tasksModel.requestToggleGrouping(modelIndex()); } } else { activateTask(); } } else if (mouse.button == Qt.LeftButton){ activateTask(); } backend.cancelHighlightWindows(); } pressed = false; if(!inAnimation && !root.latteDock) checkListHovered.startDuration(3*units.longDuration); } onWheel: { if (isSeparator || !root.mouseWheelActions || inWheelAction || inBouncingAnimation || (latteDock && (latteDock.dockIsHidden || latteDock.inSlidingIn || latteDock.inSlidingOut))){ return; } var angle = wheel.angleDelta.y / 8; //positive direction if (angle > 12) { if (isLauncher) { mouseEntered = false; inWheelAction = true; wrapper.runLauncherAnimation(); } else if (isGroupParent) { tasksWindows.activateNextTask(); } else { var taskIndex = modelIndex(); if (isMinimized) { inWheelAction = true; tasksModel.requestToggleMinimized(taskIndex); wheelActionDelayer.start(); } tasksModel.requestActivate(taskIndex); } //negative direction } else if (angle < 12) { if (isLauncher) { // do nothing } else if (isGroupParent) { tasksWindows.activatePreviousTask(); } else { var taskIndex = modelIndex(); if (isMinimized) { inWheelAction = true; tasksModel.requestToggleMinimized(taskIndex); wheelActionDelayer.start(); } tasksModel.requestActivate(taskIndex); } } } ///////////////// End Of Mouse Area Events /////////////////// ///// Handlers for Signals ///// function signalMouseWasEntered(nIndex, value){ if( index === nIndex) mouseEntered = value; } function animationStarted(){ // console.log("Animation started: " + index); inAnimation = true; } function animationEnded(){ // console.log("Animation ended: " + index); inAnimation = false; // checkListHovered.startDuration(3*units.longDuration); } function clearZoom(){ if(!root) return; if (root.globalDirectRender) wrapper.mScale = 1; else restoreAnimation.start(); } function handlerDraggingFinished(){ isDragged = false; } ///// End of Handlers ////// ///// Helper functions ///// function activateNextTask() { tasksWindows.activateNextTask(); } function activateTask() { if( mainItemContainer.isLauncher){ mouseEntered = false; wrapper.runLauncherAnimation(); } else{ if (model.IsGroupParent) { if (Latte.WindowSystem.compositingActive && backend.canPresentWindows()) { root.presentWindows(model.LegacyWinIdList); } else { if ((windowsPreviewDlg.visualParent === mainItemContainer)&&(windowsPreviewDlg.visible)) { windowsPreviewDlg.hide(3); } else { preparePreviewWindow(false); windowsPreviewDlg.show(mainItemContainer); } } } else { if (IsMinimized === true) { var i = modelIndex(); tasksModel.requestToggleMinimized(i); tasksModel.requestActivate(i); } else if (IsActive === true) { tasksModel.requestToggleMinimized(modelIndex()); } else { tasksModel.requestActivate(modelIndex()); } } } } function preparePreviewWindow(hideClose){ windowsPreviewDlg.visualParent = tooltipVisualParent; toolTipDelegate.parentTask = mainItemContainer; toolTipDelegate.parentIndex = itemIndex; toolTipDelegate.hideCloseButtons = hideClose; toolTipDelegate.appName = Qt.binding(function() { return model.AppName; }); toolTipDelegate.pidParent = Qt.binding(function() { return model.AppPid; }); toolTipDelegate.windows = Qt.binding(function() { return model.LegacyWinIdList; }); toolTipDelegate.isGroup = Qt.binding(function() { return model.IsGroupParent == true; }); toolTipDelegate.icon = Qt.binding(function() { return model.decoration; }); toolTipDelegate.launcherUrl = Qt.binding(function() { return model.LauncherUrlWithoutIcon; }); toolTipDelegate.isLauncher = Qt.binding(function() { return model.IsLauncher == true; }); toolTipDelegate.isMinimizedParent = Qt.binding(function() { return model.IsMinimized == true; }); toolTipDelegate.displayParent = Qt.binding(function() { return model.display; }); toolTipDelegate.genericName = Qt.binding(function() { return model.GenericName; }); toolTipDelegate.virtualDesktopParent = Qt.binding(function() { return model.VirtualDesktop != undefined ? model.VirtualDesktop : 0; }); toolTipDelegate.isOnAllVirtualDesktopsParent = Qt.binding(function() { return model.IsOnAllVirtualDesktops == true; }); toolTipDelegate.activitiesParent = Qt.binding(function() { return model.Activities; }); /* toolTipDelegate.parentIndex = index; toolTipDelegate.windows = Qt.binding(function() { return model.LegacyWinIdList; }); toolTipDelegate.mainText = Qt.binding(function() { return model.display; }); toolTipDelegate.icon = Qt.binding(function() { return model.decoration; }); toolTipDelegate.subText = Qt.binding(function() { return model.IsLauncher === true ? model.GenericName : generateSubText(model); }); toolTipDelegate.launcherUrl = Qt.binding(function() { return model.LauncherUrlWithoutIcon; }); toolTipDelegate.titles = tasksWindows.windowsTitles();*/ } function launcherAction(){ // if ((lastButtonClicked == Qt.LeftButton)||(lastButtonClicked == Qt.MidButton)){ inBouncingAnimation = true; root.addWaitingLauncher(mainItemContainer.launcherUrl); tasksModel.requestActivate(modelIndex()); // } } ///window previews/// function generateSubText(task) { var subTextEntries = new Array(); if (!plasmoid.configuration.showOnlyCurrentDesktop && virtualDesktopInfo.numberOfDesktops > 1 && model.IsOnAllVirtualDesktops !== true && model.VirtualDesktop != -1 && model.VirtualDesktop != undefined) { subTextEntries.push(i18n("On %1", virtualDesktopInfo.desktopNames[model.VirtualDesktop - 1])); } if (model.Activities == undefined) { return subTextEntries.join("\n"); } if (model.Activities.length == 0 && activityInfo.numberOfRunningActivities > 1) { subTextEntries.push(i18nc("Which virtual desktop a window is currently on", "Available on all activities")); } else if (model.Activities.length > 0) { var activityNames = new Array(); for (var i = 0; i < model.Activities.length; i++) { var activity = model.Activities[i]; if (plasmoid.configuration.showOnlyCurrentActivity) { if (activity != activityInfo.currentActivity) { activityNames.push(activityInfo.activityName(model.Activities[i])); } } else if (activity != activityInfo.currentActivity) { activityNames.push(activityInfo.activityName(model.Activities[i])); } } if (plasmoid.configuration.showOnlyCurrentActivity) { if (activityNames.length > 0) { subTextEntries.push(i18nc("Activities a window is currently on (apart from the current one)", "Also available on %1", activityNames.join(", "))); } } else if (activityNames.length > 0) { subTextEntries.push(i18nc("Which activities a window is currently on", "Available on %1", activityNames.join(", "))); } } return subTextEntries.join("\n"); } ///window previews//// function launcherIsPresent(url) { var activities = tasksModel.launcherActivities(url); var NULL_UUID = "00000000-0000-0000-0000-000000000000"; if (activities.indexOf(NULL_UUID) !== -1 || activities.indexOf(activityInfo.currentActivity) !== -1) return true; return false; } function modelIndex(){ return tasksModel.makeModelIndex(index); } function showContextMenu(args) { if (isSeparator) return; contextMenu = root.createContextMenu(mainItemContainer, modelIndex(), args); contextMenu.show(); } function modifierAccepted(mouse){ if (mouse.modifiers & root.modifierQt){ if ((mouse.button === Qt.LeftButton && root.modifierClick === Latte.Dock.LeftClick) || (mouse.button === Qt.MiddleButton && root.modifierClick === Latte.Dock.MiddleClick) || (mouse.button === Qt.RightButton && root.modifierClick === Latte.Dock.RightClick)) return true; } return false; } function setBlockingAnimation(value){ inBlockingAnimation = value; } function slotShowPreviewForTasks(group) { if (group === mainItemContainer) { preparePreviewWindow(true); windowsPreviewDlg.show(mainItemContainer); } } function slotPublishGeometries() { if ((isWindow || isStartup || isGroupParent) && icList && !icList.delayingRemoval) { var globalChoords = backend.globalRect(mainItemContainer); //! Magic Lamp effect doesnt like coordinates outside the screen and //! width,heights of zero value... So we now normalize the geometries //! sent in order to avoid such circumstances if (root.vertical) { globalChoords.width = 1; globalChoords.height = Math.max(root.iconSize, mainItemContainer.height); } else { globalChoords.height = 1; globalChoords.width = Math.max(root.iconSize, mainItemContainer.width); } if (root.position === PlasmaCore.Types.BottomPositioned) { globalChoords.y = plasmoid.screenGeometry.y+plasmoid.screenGeometry.height-1; } else if (root.position === PlasmaCore.Types.TopPositioned) { globalChoords.y = plasmoid.screenGeometry.y+1; } else if (root.position === PlasmaCore.Types.LeftPositioned) { globalChoords.x = plasmoid.screenGeometry.x+1; } else if (root.position === PlasmaCore.Types.RightPositioned) { globalChoords.x = plasmoid.screenGeometry.x+plasmoid.screenGeometry.width - 1; } tasksModel.requestPublishDelegateGeometry(mainItemContainer.modelIndex(), globalChoords, mainItemContainer); } } function slotWaitingLauncherRemoved(launch) { if ((isWindow || isStartup) && !visible && launch === launcherUrl) { wrapper.mScale = 1; visible = true; } } function updateAudioStreams() { if (root.dragSource !== null) { audioStreams = []; return; } var pa = pulseAudio.item; if (!pa) { audioStreams = []; return; } var streams = pa.streamsForPid(mainItemContainer.pid); if (streams.length) { pa.registerPidMatch(mainItemContainer.appName); } else { // We only want to fall back to appName matching if we never managed to map // a PID to an audio stream window. Otherwise if you have two instances of // an application, one playing and the other not, it will look up appName // for the non-playing instance and erroneously show an indicator on both. if (!pa.hasPidMatch(mainItemContainer.appName)) { streams = pa.streamsForAppName(mainItemContainer.appName); } } // fix a binding loop concerning audiostreams, the audiostreams // should be updated only when they have changed var changed = false; if (streams.length !== audioStreams.length) { changed = true; } else { for(var i=0; i= 0) mainItemContainer.lastValidIndex = mainItemContainer.itemIndex; } } // The best solution in order to catch when the wheel action ended is to // track the isMinimized state, but when the user has enabled window previews // at all times that flag doesnt work Timer { id: wheelActionDelayer interval: 200 onTriggered: mainItemContainer.inWheelAction = false; } ///Item's Removal Animation ListView.onRemove: TaskAnimations.TaskRealRemovalAnimation{ id: taskRealRemovalAnimation } }// main Item