diff --git a/containment/package/contents/ui/applet/AppletItem.qml b/containment/package/contents/ui/applet/AppletItem.qml index bdbbea63..a54fed30 100644 --- a/containment/package/contents/ui/applet/AppletItem.qml +++ b/containment/package/contents/ui/applet/AppletItem.qml @@ -1,1199 +1,1207 @@ /* * 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.7 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.kquickcontrolsaddons 2.0 import org.kde.latte.core 0.2 as LatteCore import org.kde.latte.components 1.0 as LatteComponents import "colorizer" as Colorizer import "communicator" as Communicator import "indicator" as Indicator import "../debug" as Debug Item { id: appletItem visible: false width: isInternalViewSplitter && !root.inConfigureAppletsMode ? 0 : computeWidth height: isInternalViewSplitter && !root.inConfigureAppletsMode ? 0 : computeHeight //any applets that exceed their limits should not take events from their surrounding applets clip: !isSeparator signal mousePressed(int x, int y, int button); signal mouseReleased(int x, int y, int button); property bool animationsEnabled: true property bool parabolicEffectIsSupported: true property bool canShowAppletNumberBadge: !isSeparator && !isHidden && !isLattePlasmoid && !isSpacer && !isInternalViewSplitter //! Fill Applet(s) property bool inFillCalculations: false //temp record, is used in calculations for fillWidth,fillHeight applets property bool isAutoFillApplet: { if (!applet || !applet.Layout) 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 int maxAutoFillLength: -1 //it is used in calculations for fillWidth,fillHeight applets property int minAutoFillLength: -1 //it is used in calculations for fillWidth,fillHeight applets property bool userBlocksColorizing: false property bool appletBlocksColorizing: !communicator.requires.latteSideColoringEnabled property bool appletBlocksParabolicEffect: communicator.requires.parabolicEffectLocked property bool lockZoom: false property bool isActive: (isExpanded && applet.pluginName !== root.plasmoidName && applet.pluginName !== "org.kde.activeWindowControl" && applet.pluginName !== "org.kde.plasma.appmenu") property bool isExpanded: false property bool isHidden: (applet && applet.status === PlasmaCore.Types.HiddenStatus) || (isInternalViewSplitter && !root.inConfigureAppletsMode) property bool isInternalViewSplitter: (internalSplitterId > 0) property bool isLattePlasmoid: latteApplet !== null property bool isZoomed: false property bool isSeparator: applet && (applet.pluginName === "audoban.applet.separator" || applet.pluginName === "org.kde.latte.separator") property bool isSpacer: applet && (applet.pluginName === "org.kde.latte.spacer") property bool isSystray: applet && (applet.pluginName === "org.kde.plasma.systemtray" || applet.pluginName === "org.nomad.systemtray" ) property bool firstChildOfStartLayout: index === appletItem.layouter.startLayout.firstVisibleIndex property bool firstChildOfMainLayout: index === appletItem.layouter.mainLayout.firstVisibleIndex property bool lastChildOfMainLayout: index === appletItem.layouter.mainLayout.lastVisibleIndex property bool lastChildOfEndLayout: index === appletItem.layouter.endLayout.lastVisibleIndex readonly property bool atScreenEdge: { if (root.panelAlignment !== LatteCore.Types.Justify || root.inConfigureAppletsMode || plasmoid.configuration.offset!==0) { return false; } if (root.panelAlignment === LatteCore.Types.Justify) { //! Justify case if (root.maxLengthPerCentage!==100) { return false; } if (root.isHorizontal) { if (firstChildOfStartLayout) { return latteView && latteView.x === latteView.screenGeometry.x; } else if (lastChildOfEndLayout) { return latteView && ((latteView.x + latteView.width) === (latteView.screenGeometry.x + latteView.screenGeometry.width)); } } else { if (firstChildOfStartLayout) { return latteView && latteView.y === latteView.screenGeometry.y; } else if (lastChildOfEndLayout) { return latteView && ((latteView.y + latteView.height) === (latteView.screenGeometry.y + latteView.screenGeometry.height)); } } return false; } //! [disabled] because it is probably not needed at all. If in the future there is a report //! describing a case that this would be useful this disablement choice can be rethought /*if (root.panelAlignment === LatteCore.Types.Left) { //! Left case return firstChildOfMainLayout; } else if (root.panelAlignment === LatteCore.Types.Right) { //! Right case return lastChildOfMainLayout } if (root.panelAlignment === LatteCore.Types.Top) { return firstChildOfMainLayout && latteView && latteView.y === latteView.screenGeometry.y; } else if (root.panelAlignment === LatteCore.Types.Bottom) { return lastChildOfMainLayout && latteView && ((latteView.y + latteView.height) === (latteView.screenGeometry.y + latteView.screenGeometry.height)); }*/ return false; } //applet is in starting edge property bool firstAppletInContainer: (index >=0) && ((index === layouter.startLayout.firstVisibleIndex) || (index === layouter.mainLayout.firstVisibleIndex) || (index === layouter.endLayout.firstVisibleIndex)) //applet is in ending edge property bool lastAppletInContainer: (index >=0) && ((index === layouter.startLayout.lastVisibleIndex) || (index === layouter.mainLayout.lastVisibleIndex) || (index === layouter.endLayout.lastVisibleIndex)) readonly property bool acceptMouseEvents: applet && !isLattePlasmoid && !originalAppletBehavior && !appletItem.isSeparator && !communicator.requires.parabolicEffectLocked readonly property bool originalAppletBehavior: (appletItem.parabolic.factor.zoom === 1 && !lockZoom /*hacky flag to keep Latte behavior*/) || (appletItem.parabolic.factor.zoom>1 && !parabolicEffectIsSupported) || (appletItem.parabolic.factor.zoom>1 && parabolicEffectIsSupported && lockZoom) readonly property bool isSquare: communicator.overlayLatteIconIsActive readonly property bool screenEdgeMarginSupported: communicator.requires.screenEdgeMarginSupported property int animationTime: appletItem.animations.speedFactor.normal * (1.2*appletItem.animations.duration.small) property int index: -1 property int maxWidth: root.isHorizontal ? root.height : root.width property int maxHeight: root.isHorizontal ? root.height : root.width property int internalSplitterId: 0 property int previousIndex: -1 property int spacersMaxSize: Math.max(0,Math.ceil(0.55 * metrics.iconSize) - metrics.totals.lengthEdges) property int status: applet ? applet.status : -1 //! separators tracking readonly property bool tailAppletIsSeparator: { if (isSeparator || index<0) { return false; } var tail = index - 1; while(tail>=0 && indexer.hidden.indexOf(tail)>=0) { //! when a tail applet contains sub-indexing and does not influence //! tracking is considered hidden tail = tail - 1; } if (tail >= 0 && indexer.clients.indexOf(tail)>=0) { //! tail applet contains items sub-indexing var tailBridge = indexer.getClientBridge(tail); if (tailBridge && tailBridge.client) { return tailBridge.client.lastHeadItemIsSeparator; } } // tail applet is normal return (indexer.separators.indexOf(tail)>=0); } readonly property bool headAppletIsSeparator: { if (isSeparator || index<0) { return false; } var head = index + 1; while(head>=0 && indexer.hidden.indexOf(head)>=0) { //! when a head applet contains sub-indexing and does not influence //! tracking is considered hidden head = head + 1; } if (head >= 0 && indexer.clients.indexOf(head)>=0) { //! head applet contains items sub-indexing var headBridge = indexer.getClientBridge(head); if (headBridge && headBridge.client) { return headBridge.client.firstTailItemIsSeparator; } } // head applet is normal return (indexer.separators.indexOf(head)>=0); } //! local margins readonly property bool parabolicEffectMarginsEnabled: appletItem.parabolic.factor.zoom>1 && !originalAppletBehavior && !communicator.parabolicEffectIsSupported property int lengthAppletPadding: metrics.fraction.lengthAppletPadding === -1 || parabolicEffectMarginsEnabled ? metrics.padding.length : metrics.padding.lengthApplet property int lengthAppletFullMargin: 0 property int lengthAppletFullMargins: 2 * lengthAppletFullMargin property int internalWidthMargins: { if (root.isVertical) { return metrics.totals.thicknessEdges; } /*TODO, Fitt's case: is temporary until the atScreenEdge applets are aligned properly to the corner and the wrapper is taking all the space needed in order to fill right. For atScreenEdge appplets that should be: applet size + lengthAppletPadding + lengthAppletExtMargin. The indicator should follow also the applet alignment in this in order to feel right */ return 2 * lengthAppletPadding; } property int internalHeightMargins: { if (root.isHorizontal) { return root.metrics.totals.thicknessEdges; } /*TODO,Fitt's case: is temporary until the atScreenEdge applets are aligned properly to the corner and the wrapper is taking all the space needed in order to fill right. For atScreenEdge appplets that should be: applet size + lengthAppletPadding + lengthAppletExtMargin. The indicator should follow also the applet alignment in this in order to feel right */ return 2 * lengthAppletPadding; } //! are set by the indicator property int iconOffsetX: 0 property int iconOffsetY: 0 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 latteStyleApplet: applet && ((applet.pluginName === "org.kde.latte.spacer") || (applet.pluginName === "org.kde.latte.separator")) ? (applet.children[0] ? applet.children[0] : null) : null property Item appletWrapper: applet && (applet.pluginName === root.plasmoidName )? wrapper : wrapper.wrapperContainer property Item tooltipVisualParent: titleTooltipParent readonly property alias communicator: _communicator readonly property alias wrapper: _wrapper property Item animations: null property Item indexer: null property Item layouter: null property Item metrics: null property Item parabolic: null property Item shortcuts: null property bool containsMouse: appletMouseArea.containsMouse || (isLattePlasmoid && latteApplet.containsMouse) property bool pressed: viewSignalsConnector.pressed || clickedAnimation.running //// BEGIN :: Animate Applet when a new applet is dragged in the view //when the applet moves caused by its resize, don't animate. //this is completely heuristic, but looks way less "jumpy" property bool movingForResize: false property int oldX: x property int oldY: y onXChanged: { if (root.isVertical) { return; } if (movingForResize) { movingForResize = false; return; } var draggingAppletInConfigure = root.dragOverlay && root.dragOverlay.currentApplet; var isCurrentAppletInDragging = draggingAppletInConfigure && (root.dragOverlay.currentApplet === appletItem); var dropApplet = root.dragInfo.entered && foreDropArea.visible if (isCurrentAppletInDragging || !draggingAppletInConfigure && !dropApplet) { return; } if (!root.isVertical) { translation.x = oldX - x; translation.y = 0; } else { translation.y = oldY - y; translation.x = 0; } translAnim.running = true if (!root.isVertical) { oldX = x; oldY = 0; } else { oldY = y; oldX = 0; } } onYChanged: { if (root.isHorizontal) { return; } if (movingForResize) { movingForResize = false; return; } var draggingAppletInConfigure = root.dragOverlay && root.dragOverlay.currentApplet; var isCurrentAppletInDragging = draggingAppletInConfigure && (root.dragOverlay.currentApplet === appletItem); var dropApplet = root.dragInfo.entered && foreDropArea.visible if (isCurrentAppletInDragging || !draggingAppletInConfigure && !dropApplet) { return; } if (!root.isVertical) { translation.x = oldX - x; translation.y = 0; } else { translation.y = oldY - y; translation.x = 0; } translAnim.running = true; if (!root.isVertical) { oldX = x; oldY = 0; } else { oldY = y; oldX = 0; } } transform: Translate { id: translation } NumberAnimation { id: translAnim duration: appletItem.animations.duration.large easing.type: Easing.InOutQuad target: translation properties: "x,y" to: 0 } Behavior on lengthAppletPadding { NumberAnimation { duration: 0.8 * appletItem.animations.duration.proposed easing.type: Easing.OutCubic } } //// END :: Animate Applet when a new applet is dragged in the view /// BEGIN functions function activateAppletForNeutralAreas(mouse){ //if the event is at the active indicator or spacers area then try to expand the applet, //unfortunately for other applets there is no other way to activate them yet //for example the icon-only applets var choords = mapToItem(appletItem.appletWrapper, mouse.x, mouse.y); var wrapperContainsMouse = choords.x>=0 && choords.y>=0 && choords.x=0 && mouse.y>=0 && mouse.x0); var appletNeutralAreaEnabled = !(inThicknessNeutralArea && root.dragActiveWindowEnabled); if (appletItemContainsMouse && !wrapperContainsMouse && appletNeutralAreaEnabled) { //console.log("PASSED"); latteView.extendedInterface.toggleAppletExpanded(applet.id); } else { //console.log("REJECTED"); } } function checkIndex(){ index = -1; for(var i=0; i maxSize || applet.Layout.minimumWidth > maxForMinimumSize)) || (applet && root.isVertical && (applet.height > maxSize || applet.Layout.minimumHeight > maxForMinimumSize))) && !appletItem.isSpacer && !communicator.canShowOverlaiedLatteIcon) ) { appletItem.parabolicEffectIsSupported = false; } else { appletItem.parabolicEffectIsSupported = true; } } } function slotDestroyInternalViewSplitters() { if (isInternalViewSplitter) { destroy(); } } //! pos in global root positioning function containsPos(pos) { var relPos = root.mapToItem(appletItem,pos.x, pos.y); if (relPos.x>=0 && relPos.x<=width && relPos.y>=0 && relPos.y<=height) return true; return false; } function refersEntryIndex(entryIndex) { return (entryIndex === parabolicManager.pseudoAppletIndex(appletItem.index)); } ///END functions //BEGIN connections onAppletChanged: { if (!applet) { destroy(); } } onIndexChanged: { if (appletItem.latteApplet) { root.latteAppletPos = index; } if (index>-1) { previousIndex = index; } } onIsExpandedChanged: { if (isExpanded) { root.hideTooltipLabel(); } } onIsSystrayChanged: { updateParabolicEffectIsSupported(); } onLatteAppletChanged: { if(appletItem.latteApplet){ root.latteApplet = appletItem.latteApplet; root.latteAppletContainer = appletItem; root.latteAppletPos = index; appletItem.latteApplet.latteView = root; appletItem.latteApplet.forceHidePanel = true; appletItem.latteApplet.signalPreviewsShown.connect(slotPreviewsShown); } } onIsAutoFillAppletChanged: updateParabolicEffectIsSupported(); Component.onCompleted: { checkIndex(); root.updateIndexes.connect(checkIndex); root.destroyInternalViewSplitters.connect(slotDestroyInternalViewSplitters); parabolic.sglClearZoom.connect(sltClearZoom); } Component.onDestruction: { appletItem.animations.needBothAxis.removeEvent(appletItem); if(root.latteAppletPos>=0 && root.latteAppletPos === index){ root.latteApplet = null; root.latteAppletContainer = null; root.latteAppletPos = -1; } root.updateIndexes.disconnect(checkIndex); root.destroyInternalViewSplitters.disconnect(slotDestroyInternalViewSplitters); parabolic.sglClearZoom.disconnect(sltClearZoom); if (appletItem.latteApplet) { appletItem.latteApplet.signalPreviewsShown.disconnect(slotPreviewsShown); } } //! Bindings Binding { //! is used to aboid loop binding warnings on startup target: appletItem property: "lengthAppletFullMargin" when: !communicator.inStartup value: lengthAppletPadding + metrics.margin.length; } //! Connections Connections{ target: appletItem.shortcuts onSglActivateEntryAtIndex: { + if (!appletItem.shortcuts.unifiedGlobalShortcuts) { + return; + } + var visibleIndex = appletItem.indexer.visibleIndex(appletItem.index); if (visibleIndex === entryIndex && !communicator.positionShortcutsAreSupported) { latteView.extendedInterface.toggleAppletExpanded(applet.id); } } onSglNewInstanceForEntryAtIndex: { + if (!appletItem.shortcuts.unifiedGlobalShortcuts) { + return; + } + var visibleIndex = appletItem.indexer.visibleIndex(appletItem.index); if (visibleIndex === entryIndex && !communicator.positionShortcutsAreSupported) { latteView.extendedInterface.toggleAppletExpanded(applet.id); } } } Connections { id: viewSignalsConnector target: root.latteView ? root.latteView : null enabled: !appletItem.isLattePlasmoid && !appletItem.isSeparator && !appletItem.isSpacer && !appletItem.isHidden property bool pressed: false property bool blockWheel: false onMousePressed: { if (appletItem.containsPos(pos)) { viewSignalsConnector.pressed = true; var local = appletItem.mapFromItem(root, pos.x, pos.y); appletItem.mousePressed(local.x, local.y, button); if (button === Qt.LeftButton) { appletItem.activateAppletForNeutralAreas(local); } } } onMouseReleased: { if (appletItem.containsPos(pos)) { viewSignalsConnector.pressed = false; var local = appletItem.mapFromItem(root, pos.x, pos.y); appletItem.mouseReleased(local.x, local.y, button); } } onWheelScrolled: { if (!appletItem.applet || !root.mouseWheelActions || viewSignalsConnector.blockWheel || (root.latteViewIsHidden || root.inSlidingIn || root.inSlidingOut)) { return; } blockWheel = true; scrollDelayer.start(); if (appletItem.containsPos(pos) && root.latteView.extendedInterface.appletIsExpandable(applet.id)) { var angle = angleDelta.y / 8; var expanded = root.latteView.extendedInterface.appletIsExpanded(applet.id); if ((angle > 12 && !expanded) /*positive direction*/ || (angle < -12 && expanded) /*negative direction*/) { latteView.extendedInterface.toggleAppletExpanded(applet.id); } } } } Connections { target: root.latteView ? root.latteView.extendedInterface : null enabled: !appletItem.isLattePlasmoid && !appletItem.isSeparator && !appletItem.isSpacer && !appletItem.isHidden onExpandedAppletStateChanged: { if (latteView.extendedInterface.hasExpandedApplet && appletItem.applet) { appletItem.isExpanded = latteView.extendedInterface.appletIsExpandable(appletItem.applet.id) && latteView.extendedInterface.appletIsExpanded(appletItem.applet.id); } else { appletItem.isExpanded = false; } } } ///END connections //! It is used for any communication needed with the underlying applet Communicator.Engine{ id: _communicator //set up the overlayed appletItems and properties for when a overlaiedIconItem must be presented to the user //because the plasma widgets specific implementation breaks the Latte experience onOverlayLatteIconIsActiveChanged:{ if (!overlayLatteIconIsActive && applet.opacity===0) { applet.opacity = 1; } else if (overlayLatteIconIsActive && applet.opacity>0) { applet.opacity = 0; if (applet.pluginName === "org.kde.plasma.folder") { applet.parent = wrapper.containerForOverlayIcon; applet.anchors.fill = wrapper.containerForOverlayIcon; } } } } /* Rectangle{ anchors.fill: parent color: "transparent" border.color: "green" border.width: 1 }*/ /* DEPRECATED in favor of VIEW::MouseSignalsTracking MouseArea{ id: appletMouseAreaBottom anchors.fill: parent propagateComposedEvents: true visible: (!appletMouseArea.visible || !appletMouseArea.enabled) && !root.editMode && !originalAppletBehavior onPressed: { appletItem.activateAppletForNeutralAreas(mouse); mouse.accepted = false; } onReleased: { mouse.accepted = false; } }*/ //! Main Applet Shown Area Flow{ id: appletFlow width: appletItem.computeWidth height: appletItem.computeHeight // a hidden spacer for the first element to add stability // IMPORTANT: hidden spacers must be tested on vertical !!! HiddenSpacer{id: hiddenSpacerLeft} Item { width: wrapper.width height: wrapper.height Indicator.Bridge{ id: indicatorBridge } //! Indicator Back Layer Indicator.Loader{ id: indicatorBackLayer level: Indicator.LevelOptions { id: backLevelOptions isBackground: true bridge: indicatorBridge Binding { target: appletItem property: "iconOffsetX" value: backLevelOptions.requested.iconOffsetX } Binding { target: appletItem property: "iconOffsetY" value: backLevelOptions.requested.iconOffsetY } } } ItemWrapper{ id: _wrapper TitleTooltipParent{ id: titleTooltipParent metrics: appletItem.metrics parabolic: appletItem.parabolic } } //! The Applet Colorizer Colorizer.Applet { id: appletColorizer anchors.fill: parent opacity: mustBeShown ? 1 : 0 readonly property bool mustBeShown: colorizerManager.mustBeShown && !appletItem.userBlocksColorizing && !appletItem.appletBlocksColorizing && !appletItem.isInternalViewSplitter Behavior on opacity { NumberAnimation { duration: 1.2 * appletItem.animations.duration.proposed easing.type: Easing.OutCubic } } } //! Indicator Front Layer Indicator.Loader{ id: indicatorFrontLayer level: Indicator.LevelOptions { isForeground: true bridge: indicatorBridge } } //! Applet Shortcut Visual Badge Item { id: shortcutBadgeContainer width: { if (root.isHorizontal) { return appletItem.metrics.iconSize * wrapper.zoomScale } else { return badgeThickness; } } height: { if (root.isHorizontal) { return badgeThickness; } else { return appletItem.metrics.iconSize * wrapper.zoomScale } } readonly property int badgeThickness: { if (plasmoid.location === PlasmaCore.Types.BottomEdge || plasmoid.location === PlasmaCore.Types.RightEdge) { return ((appletItem.metrics.iconSize + appletItem.metrics.margin.thickness) * wrapper.zoomScale) + appletItem.metrics.margin.screenEdge; } return ((appletItem.metrics.iconSize + appletItem.metrics.margin.thickness) * wrapper.zoomScale); } ShortcutBadge{ anchors.fill: parent } states:[ State{ name: "horizontal" when: plasmoid.formFactor === PlasmaCore.Types.Horizontal AnchorChanges{ target: shortcutBadgeContainer; anchors.horizontalCenter: parent.horizontalCenter; anchors.verticalCenter: undefined; anchors.right: undefined; anchors.left: undefined; anchors.top: undefined; anchors.bottom: parent.bottom; } }, State{ name: "vertical" when: plasmoid.formFactor === PlasmaCore.Types.Vertical AnchorChanges{ target: shortcutBadgeContainer; anchors.horizontalCenter: undefined; anchors.verticalCenter: parent.verticalCenter; anchors.right: parent.right; anchors.left: undefined; anchors.top: undefined; anchors.bottom: undefined; } } ] } } // a hidden spacer on the right for the last item to add stability HiddenSpacer{id: hiddenSpacerRight; rightSpacer: true} }// Flow with hidden spacers inside //Busy Indicator PlasmaComponents.BusyIndicator { z: 1000 visible: applet && applet.busy running: visible anchors.centerIn: parent width: Math.min(parent.width, parent.height) height: width } Loader { id: addingAreaLoader width: root.isHorizontal ? parent.width : parent.width - appletItem.metrics.margin.screenEdge height: root.isHorizontal ? parent.height - appletItem.metrics.margin.screenEdge : parent.height active: isLattePlasmoid sourceComponent: LatteComponents.AddingArea{ id: addingAreaItem anchors.fill: parent // width: root.isHorizontal ? parent.width : parent.width - appletItem.metrics.margin.screenEdge // height: root.isHorizontal ? parent.height - appletItem.metrics.margin.screenEdge : parent.height radius: appletItem.metrics.iconSize/10 opacity: root.addLaunchersMessage ? 1 : 0 backgroundOpacity: 0.75 duration: appletItem.animations.speedFactor.current title: i18n("Tasks Area") } //! AddingAreaItem States states:[ State{ name: "bottom" when: plasmoid.location === PlasmaCore.Types.BottomEdge AnchorChanges{ target: addingAreaLoader anchors.horizontalCenter: parent.horizontalCenter; anchors.verticalCenter: undefined; anchors.right: undefined; anchors.left: undefined; anchors.top: undefined; anchors.bottom: parent.bottom; } PropertyChanges{ target: addingAreaLoader anchors.leftMargin: 0; anchors.rightMargin: 0; anchors.topMargin:0; anchors.bottomMargin: appletItem.metrics.margin.screenEdge; anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0; } }, State{ name: "top" when: plasmoid.location === PlasmaCore.Types.TopEdge AnchorChanges{ target: addingAreaLoader anchors.horizontalCenter: parent.horizontalCenter; anchors.verticalCenter: undefined; anchors.right: undefined; anchors.left: undefined; anchors.top: parent.top; anchors.bottom: undefined; } PropertyChanges{ target: addingAreaLoader anchors.leftMargin: 0; anchors.rightMargin: 0; anchors.topMargin: appletItem.metrics.margin.screenEdge; anchors.bottomMargin: 0; anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0; } }, State{ name: "left" when: plasmoid.location === PlasmaCore.Types.LeftEdge AnchorChanges{ target: addingAreaLoader anchors.horizontalCenter: undefined; anchors.verticalCenter: parent.verticalCenter; anchors.right: undefined; anchors.left: parent.left; anchors.top: undefined; anchors.bottom: undefined; } PropertyChanges{ target: addingAreaLoader anchors.leftMargin: appletItem.metrics.margin.screenEdge; anchors.rightMargin: 0; anchors.topMargin:0; anchors.bottomMargin: 0; anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0; } }, State{ name: "right" when: plasmoid.location === PlasmaCore.Types.RightEdge AnchorChanges{ target: addingAreaLoader anchors.horizontalCenter: undefined; anchors.verticalCenter: parent.verticalCenter; anchors.right: parent.right; anchors.left: undefined; anchors.top: undefined; anchors.bottom: undefined; } PropertyChanges{ target: addingAreaLoader anchors.leftMargin: 0; anchors.rightMargin: appletItem.metrics.margin.screenEdge; anchors.topMargin:0; anchors.bottomMargin: 0; anchors.horizontalCenterOffset: 0; anchors.verticalCenterOffset: 0; } } ] } MouseArea{ id: appletMouseArea anchors.fill: parent enabled: visible hoverEnabled: latteApplet ? false : true 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: acceptMouseEvents property bool blockWheel: false onEntered: { appletItem.parabolic.stopRestoreZoomTimer(); if (restoreAnimation.running) { restoreAnimation.stop(); } if (!(isSeparator || isSpacer)) { root.showTooltipLabel(appletItem, applet.title); } if (originalAppletBehavior || communicator.requires.parabolicEffectLocked || !parabolicEffectIsSupported) { return; } if (root.isHalfShown || (root.latteApplet && (root.latteApplet.noTasksInAnimation>0 || root.latteApplet.contextMenu))) { return; } if (root.isHorizontal){ layoutsContainer.currentSpot = mouseX; wrapper.calculateScales(mouseX); } else{ layoutsContainer.currentSpot = mouseY; wrapper.calculateScales(mouseY); } } onExited:{ if (communicator.appletIconItemIsShown()) { communicator.setAppletIconItemActive(false); } root.hideTooltipLabel(); if (appletItem.parabolic.factor.zoom>1){ appletItem.parabolic.startRestoreZoomTimer(); } } onPositionChanged: { if (originalAppletBehavior || !parabolicEffectIsSupported) { mouse.accepted = false; return; } if (root.isHalfShown || (root.latteApplet && (root.latteApplet.noTasksInAnimation>0 || root.latteApplet.contextMenu))) { return; } var rapidMovement = appletItem.parabolic.lastIndex>=0 && Math.abs(appletItem.parabolic.lastIndex-index)>1; if (rapidMovement) { parabolic.setDirectRenderingEnabled(true); } if( ((wrapper.zoomScale == 1 || wrapper.zoomScale === appletItem.parabolic.factor.zoom) && !parabolic.directRenderingEnabled) || parabolic.directRenderingEnabled) { if (root.isHorizontal){ var step = Math.abs(layoutsContainer.currentSpot-mouse.x); if (step >= appletItem.animations.hoverPixelSensitivity){ layoutsContainer.currentSpot = mouse.x; wrapper.calculateScales(mouse.x); } } else{ var step = Math.abs(layoutsContainer.currentSpot-mouse.y); if (step >= appletItem.animations.hoverPixelSensitivity){ layoutsContainer.currentSpot = mouse.y; wrapper.calculateScales(mouse.y); } } } mouse.accepted = false; } //! these are needed in order for these events to be really forwarded underneath //! otherwise there were applets that did not receive them e.g. lock/logout applet //! when parabolic effect was used onPressed: mouse.accepted = false; onReleased: mouse.accepted = false; } //! Debug Elements Loader{ anchors.bottom: parent.bottom anchors.left: parent.left active: root.debugModeLayouter sourceComponent: Debug.Tag{ label.text: (root.isHorizontal ? appletItem.width : appletItem.height) + labeltext label.color: appletItem.isAutoFillApplet ? "green" : "white" readonly property string labeltext: { if (appletItem.isAutoFillApplet) { return " / max_fill:"+appletItem.maxAutoFillLength + " / min_fill:"+appletItem.minAutoFillLength; } return ""; } } } //! A timer is needed in order to handle also touchpads that probably //! send too many signals very fast. This way the signals per sec are limited. //! The user needs to have a steady normal scroll in order to not //! notice a annoying delay Timer{ id: scrollDelayer interval: 500 onTriggered: viewSignalsConnector.blockWheel = 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 * appletItem.animationTime easing.type: Easing.InCubic } } /////Clicked Animation///// SequentialAnimation{ id: clickedAnimation alwaysRunToEnd: true running: appletItem.isSquare && !originalAppletBehavior && appletItem.pressed && (appletItem.animations.speedFactor.current > 0) && !indicators.info.providesClickedAnimation ParallelAnimation{ PropertyAnimation { target: wrapper.clickedEffect property: "brightness" to: -0.35 duration: appletItem.animations.duration.large easing.type: Easing.OutQuad } } ParallelAnimation{ PropertyAnimation { target: wrapper.clickedEffect property: "brightness" to: 0 duration: appletItem.animations.duration.large easing.type: Easing.OutQuad } } } //END animations } diff --git a/declarativeimports/abilities/applets/PositionShortcuts.qml b/declarativeimports/abilities/applets/PositionShortcuts.qml index 164d37e0..c9b67b27 100644 --- a/declarativeimports/abilities/applets/PositionShortcuts.qml +++ b/declarativeimports/abilities/applets/PositionShortcuts.qml @@ -1,57 +1,66 @@ /* * Copyright 2020 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 org.kde.latte.abilities.definitions 0.1 as AbilityDefinition AbilityDefinition.PositionShortcuts { id: shortcuts property Item bridge: null readonly property bool isActive: bridge !== null property bool isStealingGlobalPositionShortcuts: false readonly property bool showPositionShortcutBadges: ref.shortcuts.showPositionShortcutBadges + readonly property bool isEnabled: { + if (bridge) { + return bridge.shortcuts.host.unifiedGlobalShortcuts + || (!bridge.shortcuts.host.unifiedGlobalShortcuts && bridge.shortcuts.appletIndex === bridge.shortcuts.host.appletIdStealingPositionShortcuts); + } + + return true; + } + signal disabledIsStealingGlobalPositionShortcuts(); Item { id: ref readonly property Item shortcuts: bridge ? bridge.shortcuts.host : local } onIsActiveChanged: { if (isActive) { bridge.shortcuts.client = shortcuts; } } Component.onCompleted: { if (isActive) { bridge.shortcuts.client = shortcuts; } } Component.onDestruction: { if (isActive) { bridge.shortcuts.client = null; } } } diff --git a/plasmoid/package/contents/ui/abilities/PositionShortcuts.qml b/plasmoid/package/contents/ui/abilities/PositionShortcuts.qml index c975b60d..6aa3c8a7 100644 --- a/plasmoid/package/contents/ui/abilities/PositionShortcuts.qml +++ b/plasmoid/package/contents/ui/abilities/PositionShortcuts.qml @@ -1,29 +1,39 @@ /* * Copyright 2020 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.7 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.latte.abilities.applets 0.1 as AppletAbility AppletAbility.PositionShortcuts { id: shortcuts + + function shortcutIndex(entryIndex) { + if (!bridge) { + return indexer.visibleIndex(entryIndex); + } + + var base = bridge.indexer.host.visibleIndex(bridge.shortcuts.appletIndex); + + return (indexer.visibleIndex(entryIndex) - base); + } } diff --git a/plasmoid/package/contents/ui/task/ShortcutBadge.qml b/plasmoid/package/contents/ui/task/ShortcutBadge.qml index 938c5f86..d3a03fe7 100644 --- a/plasmoid/package/contents/ui/task/ShortcutBadge.qml +++ b/plasmoid/package/contents/ui/task/ShortcutBadge.qml @@ -1,86 +1,88 @@ /* * Copyright 2019 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.7 import QtGraphicalEffects 1.0 import org.kde.latte.components 1.0 as LatteComponents Loader{ id: shorcutBadge anchors.fill: iconImageBuffer - active: taskItem.shortcuts.showPositionShortcutBadges && !taskItem.isSeparator && !taskItem.isHidden + active: taskItem.shortcuts.showPositionShortcutBadges && !taskItem.isSeparator && !taskItem.isHidden && taskItem.shortcuts.isEnabled asynchronous: true visible: badgeString !== "" property int fixedIndex:-1 property string badgeString: (shorcutBadge.fixedIndex>=1 && shorcutBadge.fixedIndex<20 && taskItem.shortcuts.badges.length===19) ? taskItem.shortcuts.badges[shorcutBadge.fixedIndex-1] : "" onActiveChanged: { if (active && taskItem.shortcuts.showPositionShortcutBadges) { - fixedIndex = taskItem.indexer.visibleIndex(taskItem.itemIndex); + fixedIndex = taskItem.shortcuts.shortcutIndex(taskItem.itemIndex); } else { fixedIndex = -1; } } Component.onCompleted: { - fixedIndex = taskItem.indexer.visibleIndex(taskItem.itemIndex); + if (taskItem.shortcuts.isEnabled) { + fixedIndex = taskItem.shortcuts.shortcutIndex(taskItem.itemIndex); + } } sourceComponent: Item{ Loader{ anchors.fill: taskNumber active: root.enableShadows && graphicsSystem.isAccelerated sourceComponent: DropShadow{ color: root.appShadowColor fast: true samples: 2 * radius source: taskNumber radius: root.appShadowSize/2 verticalOffset: 2 } } LatteComponents.BadgeText { id: taskNumber // when iconSize < 48, height is always = 24, height / iconSize > 50% // we prefer center aligned badges to top-left aligned ones property bool centerInParent: taskItem.metrics.iconSize < 48 anchors.left: centerInParent? undefined : parent.left anchors.top: centerInParent? undefined : parent.top anchors.centerIn: centerInParent? parent : undefined minimumWidth: 0.4 * (wrapper.mScale * taskItem.metrics.iconSize) height: Math.max(24, 0.4 * (wrapper.mScale * taskItem.metrics.iconSize)) style3d: root.badges3DStyle textValue: shorcutBadge.badgeString borderColor: root.lightTextColor showNumber: false showText: true proportion: 0 radiusPerCentage: 100 } } } diff --git a/plasmoid/package/contents/ui/task/TaskItem.qml b/plasmoid/package/contents/ui/task/TaskItem.qml index 75499a7f..55e7ce74 100644 --- a/plasmoid/package/contents/ui/task/TaskItem.qml +++ b/plasmoid/package/contents/ui/task/TaskItem.qml @@ -1,1683 +1,1691 @@ /* * 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.core 0.2 as LatteCore import org.kde.latte.private.tasks 0.1 as LatteTasks import "animations" as TaskAnimations import "indicator" as Indicator MouseArea{ id: taskItem visible: false //true//(isStartup && animations.speedFactor.current !== 0) ? false : true anchors.bottom: (root.location === PlasmaCore.Types.BottomEdge) ? parent.bottom : undefined anchors.top: (root.location === PlasmaCore.Types.TopEdge) ? parent.top : undefined anchors.left: (root.location === PlasmaCore.Types.LeftEdge) ? parent.left : undefined anchors.right: (root.location === PlasmaCore.Types.RightEdge) ? parent.right : undefined objectName: "TaskItem" width: { if (!visible) return 0; if (isSeparator) { if (root.vertical) { return taskItem.metrics.totals.thickness + taskItem.metrics.margin.screenEdge; } else { if (root.dragSource || !root.parabolicEffectEnabled) { return LatteCore.Environment.separatorLength+2*taskItem.metrics.margin.length; } } return 0; } if (root.vertical) { return wrapper.width; } else { return hiddenSpacerLeft.width+wrapper.width+hiddenSpacerRight.width; } } /*onWidthChanged: { console.log("T: " + itemIndex + " - " + launcherUrl + " - " + width + " _ "+ hiddenSpacerLeft.width + " _ " + wrapper.width + " _ " + hiddenSpacerRight.width); }*/ height: { if (!visible) return 0; if (isSeparator) { if (!root.vertical) { return taskItem.metrics.totals.thickness + taskItem.metrics.margin.screenEdge; } else { if (root.dragSource || !root.parabolicEffectEnabled) { return LatteCore.Environment.separatorLength+2*taskItem.metrics.margin.length; } } return 0; } if (root.vertical) { return hiddenSpacerLeft.height + wrapper.height + hiddenSpacerRight.height; } else { return wrapper.height; } } acceptedButtons: Qt.LeftButton | Qt.MidButton | Qt.RightButton hoverEnabled: visible && (!inAnimation) && (!IsStartup) && (!root.taskInAnimation) &&(!inBouncingAnimation) && !isSeparator // hoverEnabled: false //opacity : isSeparator && (hiddenSpacerLeft.neighbourSeparator || hiddenSpacerRight.neighbourSeparator) ? 0 : 1 property bool buffersAreReady: false property bool delayingRemove: ListView.delayRemove property bool scalesUpdatedOnce: false //states that exist in windows in a Group of windows property bool hasActive: isActive property bool hasMinimized: (IsGroupParent === true) ? subWindows.hasMinimized : isMinimized property bool hasShown: (IsGroupParent === true) ? subWindows.hasShown : !isMinimized && isWindow property bool inAttention: isDemandingAttention && plasmoid.status === PlasmaCore.Types.RequiresAttentionStatus ? true : false /*animations flags*/ property bool inAnimation: true property bool inAddRemoveAnimation: true property bool inAttentionAnimation: false property bool inBlockingAnimation: false property bool inBouncingAnimation: false property bool inFastRestoreAnimation: false property bool inMimicParabolicAnimation: false property bool inNewWindowAnimation: false property real mimicParabolicScale: -1 property bool inPopup: false property bool inRemoveStage: false property bool isAbleToShowPreview: true property bool isActive: (IsActive === true) ? true : false property bool isDemandingAttention: (IsDemandingAttention === true) ? true : false property bool isDragged: false property bool isGroupable: (IsGroupable === true) ? true : false property bool isGroupParent: (IsGroupParent === true) ? true : false readonly property bool isHidden: !visible || isForcedHidden property bool isForcedHidden: 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 canPublishGeometries: (isWindow || isStartup || isGroupParent) && visible && width>=taskItem.metrics.iconSize && height>=taskItem.metrics.iconSize && !taskItem.delayingRemove && (wrapper.mScale===1 || wrapper.mScale===taskItem.parabolic.factor.zoom) //don't publish during zoom animation property bool hoveredFromDragging: (mouseHandler.hoveredItem === taskItem) || (mouseHandler.ignoredItem === taskItem) property bool pressed: false property bool wheelIsBlocked: false property int animationTime: (taskItem.animations.active ? taskItem.animations.speedFactor.current : 2) * (1.2 *taskItem.animations.duration.small) property int badgeIndicator: 0 //it is used from external apps 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*taskItem.metrics.iconSize) - taskItem.metrics.totals.lengthEdges) property int windowsCount: subWindows.windowsCount property int windowsMinimizedCount: subWindows.windowsMinimized //! are set by the indicator property int iconOffsetX: 0 property int iconOffsetY: 0 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 && LauncherUrlWithoutIcon !== null) ? LauncherUrlWithoutIcon : "" property string modelLauncherUrlWithIcon: (LauncherUrl && LauncherUrl !== null) ? LauncherUrl : "" property string launcherUrl: "" property string launcherUrlWithIcon: "" property string launcherName: "" property Item tooltipVisualParent: wrapper.titleTooltipVisualParent property Item previewsVisualParent: wrapper.previewsTooltipVisualParent property Item wrapperAlias: wrapper //abilities property Item animations: null property Item indexer: null property Item metrics: null property Item parabolic: null property Item requires: null property Item shortcuts: null onModelLauncherUrlChanged: { if (modelLauncherUrl !== ""){ launcherUrl = modelLauncherUrl; //!extract the launcherName if possible var nameStarts = launcherUrl.lastIndexOf("/"); if (nameStarts === -1){ nameStarts = launcherUrl.lastIndexOf(":"); } var nameEnds = launcherUrl.lastIndexOf(".desktop"); if (nameStarts!==-1 && nameEnds!==-1 && nameStarts=0 && taskItem.indexer.hidden.indexOf(tail)>=0) { tail = tail - 1; } var hasTailItemSeparator = taskItem.indexer.separators.indexOf(tail)>=0; if (!hasTailItemSeparator && itemIndex === taskItem.indexer.firstVisibleItemIndex){ return taskItem.indexer.tailAppletIsSeparator; } return hasTailItemSeparator; } readonly property bool headItemIsSeparator: { if (isSeparator || itemIndex < 0 ) { return false; } var head = index + 1; while(head>=0 && taskItem.indexer.hidden.indexOf(head)>=0) { head = head + 1; } var hasHeadItemSeparator = taskItem.indexer.separators.indexOf(head)>=0; if (!hasHeadItemSeparator && itemIndex === taskItem.indexer.lastVisibleItemIndex){ return taskItem.indexer.headAppletIsSeparator; } return hasHeadItemSeparator; } ////// Audio streams ////// property Item audioStreamOverlay property var audioStreams: [] readonly property bool hasAudioStream: root.showAudioBadge && 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: taskItem.animations.speedFactor.current * taskItem.animations.duration.large } } Loader{ anchors.fill: parent active: latteView && latteView.debugMode sourceComponent: Rectangle{ anchors.fill: parent color: "transparent" border.color: "blue" border.width: 1 } } SubWindows{ id: subWindows property int previousCount: 0 onWindowsCountChanged: { if (root.showWindowsOnlyFromLaunchers && !root.indicatorsEnabled) { return; } if ((windowsCount >= 2) && (windowsCount > previousCount) && !(taskItem.containsMouse || parabolicManager.neighbourIsHovered(itemIndex)) ){ if(root.dragSource == null) taskItem.groupWindowAdded(); } else if ((windowsCount >=1) &&(windowsCount < previousCount)){ //sometimes this is triggered in dragging with no reason if(root.dragSource == null && !taskItem.delayingRemove) taskItem.groupWindowRemoved(); } if (windowsCount>=1) { taskItem.slotPublishGeometries(); } //! workaround in order to update correctly the previousCount //! windowsCount can not return to zero because is such case //! the window task is removed and the launcher is added from //! libtaskmanager if (windowsCount>=1) { previousCount = windowsCount; } } } Loader { id: isSeparatorRectangle active: (opacityN>0) width: taskItem.width height: taskItem.height anchors.centerIn: separatorItem property real opacityN: isSeparator && root.contextMenu && root.contextMenu.visualParent === taskItem ? 1 : 0 Behavior on opacityN { NumberAnimation { duration: taskItem.animations.speedFactor.current * taskItem.animations.duration.large } } sourceComponent: Rectangle{ anchors.fill: parent opacity: isSeparatorRectangle.opacityN radius: 3 property color tempColor: theme.highlightColor color: tempColor border.width: 1 border.color: theme.highlightColor onTempColorChanged: tempColor.a = 0.35; } } Item{ id:separatorItem anchors.bottom: (root.location === PlasmaCore.Types.BottomEdge) ? parent.bottom : undefined anchors.top: (root.location === PlasmaCore.Types.TopEdge) ? parent.top : undefined anchors.left: (root.location === PlasmaCore.Types.LeftEdge) ? parent.left : undefined anchors.right: (root.location === PlasmaCore.Types.RightEdge) ? parent.right : undefined anchors.horizontalCenter: !root.vertical ? parent.horizontalCenter : undefined anchors.verticalCenter: root.vertical ? parent.verticalCenter : undefined anchors.bottomMargin: (root.location === PlasmaCore.Types.BottomEdge) ? margin : 0 anchors.topMargin: (root.location === PlasmaCore.Types.TopEdge) ? margin : 0 anchors.leftMargin: (root.location === PlasmaCore.Types.LeftEdge) ? margin : 0 anchors.rightMargin: (root.location === PlasmaCore.Types.RightEdge) ? margin : 0 opacity: (separatorShadow.active) || forceHiddenState ? 0 : 0.4 visible: taskItem.isSeparator width: root.vertical ? taskItem.metrics.iconSize : ((root.dragSource || root.editMode) ? LatteCore.Environment.separatorLength+taskItem.metrics.totals.lengthEdges: 1) height: !root.vertical ? taskItem.metrics.iconSize : ((root.dragSource || root.editMode) ? LatteCore.Environment.separatorLength+taskItem.metrics.totals.lengthEdges: 1) property bool forceHiddenState: false readonly property int margin: taskItem.metrics.margin.screenEdge + metrics.margin.thickness Behavior on opacity { NumberAnimation { duration: taskItem.animations.speedFactor.current * taskItem.animations.duration.large } } Connections{ target: root //! During dock sliding-in because the parabolic effect isnt trigerred //! immediately but we wait first the dock to go to its final normal //! place we might miss the activation of the parabolic effect. //! By catching that signal we are trying to solve this. onDockIsShownCompletelyChanged: { if (dockIsShownCompletely && taskItem.containsMouse) { if (root.vertical) { taskItem.mousePosChanged(taskItem.mouseY); } else { taskItem.mousePosChanged(taskItem.mouseX); } } } onShowWindowsOnlyFromLaunchersChanged: { if (!root.editMode) { return; } taskItem.updateVisibilityBasedOnLaunchers(); } onInActivityChangeChanged: { if (root.showWindowsOnlyFromLaunchers && !root.inActivityChange) { taskItem.updateVisibilityBasedOnLaunchers(); } } } Rectangle { anchors.centerIn: parent width: root.vertical ? taskItem.metrics.iconSize - 4 : 1 height: !root.vertical ? taskItem.metrics.iconSize - 4 : 1 color: enforceLattePalette ? latteBridge.palette.textColor : theme.textColor } } ///Shadow in tasks Loader{ id: separatorShadow anchors.fill: separatorItem active: root.enableShadows && isSeparator && graphicsSystem.isAccelerated opacity: separatorItem.forceHiddenState ? 0 : 0.4 Behavior on opacity { NumberAnimation { duration: taskItem.animations.speedFactor.current * taskItem.animations.duration.large } } sourceComponent: DropShadow{ anchors.fill: parent color: root.appShadowColor fast: true 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 !!! HiddenSpacer{ id:hiddenSpacerLeft;} Item{ width: wrapper.width height: wrapper.height Indicator.Bridge{ id: indicatorBridge } Indicator.Loader{ id: indicatorBackLayer level: Indicator.LevelOptions { id: backLevelOptions isBackground: true bridge: indicatorBridge Binding { target: taskItem property: "iconOffsetX" value: backLevelOptions.requested.iconOffsetX } Binding { target: taskItem property: "iconOffsetY" value: backLevelOptions.requested.iconOffsetY } } } Wrapper{id: wrapper} Indicator.Loader{ id: indicatorFrontLayer level: Indicator.LevelOptions { isForeground: true bridge: indicatorBridge } } } // a hidden spacer on the right for the last item to add stability HiddenSpacer{ id:hiddenSpacerRight; rightSpacer: true } }// Flow with hidden spacers inside Component { id: taskInitComponent Timer { id: timer interval: 800 repeat: false onTriggered: { // taskItem.hoverEnabled = true; slotPublishGeometries(); if (latteView && latteView.debugModeTimers) { console.log("plasmoid timer: taskInitComponentTimer called..."); } 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() onCanPublishGeometriesChanged: { if (canPublishGeometries) { slotPublishGeometries(); taskInitComponent.createObject(taskItem); } } onItemIndexChanged: { if (itemIndex>=0) { lastValidTimer.start(); } } onLastValidIndexChanged: { if (lastValidIndex>=0 && lastValidIndex parabolicManager.lastRealTaskIndex)) { parabolicManager.updateTasksEdgesIndexes(); } } } onIsDraggedChanged: { if(isDragged && (!root.inConfigureAppletsMode)){ root.dragSource = taskItem; dragHelper.startDrag(taskItem, model.MimeType, model.MimeData, model.LauncherUrlWithoutIcon, model.decoration); pressX = -1; pressY = -1; } } onIsMinimizedChanged: { checkWindowsStates(); } onIsActiveChanged: { checkWindowsStates(); if (isActive) { scrollableList.focusOn(taskItem); } } onIsSeparatorChanged: { if (isSeparator) { if (tasksExtendedManager.isLauncherToBeMoved(launcherUrl) && itemIndex>=0) { tasksExtendedManager.moveLauncherToCorrectPos(launcherUrl, itemIndex); } } } onLauncherUrlChanged: updateBadge(); ////// End of Values Changes ///// ///////////////// Mouse Area Events /////////////////// onEntered: { taskItem.parabolic.stopRestoreZoomTimer(); restoreAnimation.stop(); if ((taskItem.parabolic.local.lastIndex !== itemIndex) && isLauncher && windowsPreviewDlg.visible) { windowsPreviewDlg.hide(1); } if (root.latteView && !root.showPreviews && root.titleTooltips){ showTitleTooltip(); } //! show previews if enabled if(isAbleToShowPreview && ((root.showPreviews && windowsPreviewDlg.activeItem !== taskItem) || root.highlightWindows)){ if (hoveredTimerObj) { //! don't delay showing preview in normal states, //! that is when the dock wasn't hidden if (!hoveredTimerObj.running) { hoveredTimerObj.start(); } } else { if (!root.disableAllWindowsFunctionality) { hoveredTimerObj = hoveredTimerComponent.createObject(taskItem); } } } if (root.autoScrollTasksEnabled) { scrollableList.autoScrollFor(taskItem, false); } if (root.latteView && root.latteView.isHalfShown) { return; } } // IMPORTANT: This must be improved ! even for small milliseconds it reduces performance onExited: { scalesUpdatedOnce = false; isAbleToShowPreview = true; if (root.latteView && (!root.showPreviews || (root.showPreviews && isLauncher))){ root.latteView.hideTooltipLabel(); } if (root.showPreviews) { root.hidePreview(17.5); } if (taskItem.parabolic.factor.zoom>1){ taskItem.parabolic.startRestoreZoomTimer(); } } //! mouseX-Y values are delayed to be updated onEntered events and at the same time //! onPositionChanged signal may be delayed. we can fix this by don't delay at all //! when mouseX-Y is updated based on the plasmoid formFactor function mousePosChanged(mousePos) { if (mousePos<0 || (inBlockingAnimation && !(inAttentionAnimation||inFastRestoreAnimation||inMimicParabolicAnimation))) return; if (root.latteView && root.latteView.isHalfShown) { return; } if((inAnimation == false)&&(!root.taskInAnimation)&&(!root.disableRestoreZoom) && hoverEnabled){ var rapidMovement = taskItem.parabolic.local.lastIndex>=0 && Math.abs(taskItem.parabolic.local.lastIndex-itemIndex)>1; if (rapidMovement) { taskItem.parabolic.setDirectRenderingEnabled(true); } if( ((wrapper.mScale == 1 || wrapper.mScale === taskItem.parabolic.factor.zoom) && !taskItem.parabolic.directRenderingEnabled) || taskItem.parabolic.directRenderingEnabled || !scalesUpdatedOnce) { if(root.dragSource == null){ var step = Math.abs(icList.currentSpot-mousePos); if (step >= taskItem.animations.hoverPixelSensitivity){ icList.currentSpot = mousePos; wrapper.calculateScales(mousePos); } } } } } onMouseXChanged: { if (!root.vertical) { mousePosChanged(mouseX); } } onMouseYChanged: { if (root.vertical) { mousePosChanged(mouseY); } } onPositionChanged: { if ((inBlockingAnimation && !(inAttentionAnimation||inFastRestoreAnimation||inMimicParabolicAnimation))) return; if (root.latteView && root.latteView.isHalfShown) { return; } if((inAnimation == false)&&(!root.taskInAnimation)&&(!root.disableRestoreZoom) && hoverEnabled){ // mouse.button is always 0 here, hence checking with mouse.buttons if (pressX != -1 && mouse.buttons == Qt.LeftButton && isDragged && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y) ) { root.dragSource = taskItem; dragHelper.startDrag(taskItem, model.MimeType, model.MimeData, model.LauncherUrlWithoutIcon, model.decoration); pressX = -1; pressY = -1; } } } onContainsMouseChanged:{ if(!containsMouse && !inAnimation) { pressed=false; } ////disable hover effect/// if (isWindow && root.highlightWindows && !containsMouse) { root.windowsHovered( root.plasma515 ? model.WinIdList : model.LegacyWinIdList , false); } } onPressed: { //console.log("Pressed Task Delegate.."); if (LatteCore.WindowSystem.compositingActive && !LatteCore.WindowSystem.isPlatformWayland) { if(root.leftClickAction !== LatteTasks.Types.PreviewWindows) { isAbleToShowPreview = false; windowsPreviewDlg.hide(2); } } slotPublishGeometries(); 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(taskItem); } 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 && !isSeparator) { showContextMenu({showAllPlaces: true}) } else { showContextMenu(); } } } onReleased: { //console.log("Released Task Delegate..."); if (draggingResistaner != null){ draggingResistaner.destroy(); draggingResistaner = null; } if(pressed && (!inBlockingAnimation || inAttentionAnimation) && !isSeparator){ if (modifierAccepted(mouse) && !root.disableAllWindowsFunctionality){ if( !taskItem.isLauncher ){ if (root.modifierClickAction == LatteTasks.Types.NewInstance) { tasksModel.requestNewInstance(modelIndex()); } else if (root.modifierClickAction == LatteTasks.Types.Close) { tasksModel.requestClose(modelIndex()); } else if (root.modifierClickAction == LatteTasks.Types.ToggleMinimized) { tasksModel.requestToggleMinimized(modelIndex()); } else if ( root.modifierClickAction == LatteTasks.Types.CycleThroughTasks) { if (isGroupParent) subWindows.activateNextTask(); else activateTask(); } else if (root.modifierClickAction == LatteTasks.Types.ToggleGrouping) { tasksModel.requestToggleGrouping(modelIndex()); } } else { activateTask(); } } else if (mouse.button == Qt.MidButton && !root.disableAllWindowsFunctionality){ if( !taskItem.isLauncher ){ if (root.middleClickAction == LatteTasks.Types.NewInstance) { tasksModel.requestNewInstance(modelIndex()); } else if (root.middleClickAction == LatteTasks.Types.Close) { tasksModel.requestClose(modelIndex()); } else if (root.middleClickAction == LatteTasks.Types.ToggleMinimized) { tasksModel.requestToggleMinimized(modelIndex()); } else if ( root.middleClickAction == LatteTasks.Types.CycleThroughTasks) { if (isGroupParent) subWindows.activateNextTask(); else activateTask(); } else if (root.middleClickAction == LatteTasks.Types.ToggleGrouping) { tasksModel.requestToggleGrouping(modelIndex()); } } else { activateTask(); } } else if (mouse.button == Qt.LeftButton){ if( !taskItem.isLauncher ){ if ( (root.leftClickAction === LatteTasks.Types.PreviewWindows && isGroupParent) || ( (LatteCore.WindowSystem.isPlatformWayland || !LatteCore.WindowSystem.compositingActive) && root.leftClickAction === LatteTasks.Types.PresentWindows && isGroupParent) ) { if(windowsPreviewDlg.activeItem !== taskItem || !windowsPreviewDlg.visible){ showPreviewWindow(); } else { root.forcePreviewsHiding(21.1); } } else if ( (root.leftClickAction === LatteTasks.Types.PresentWindows && !(isGroupParent && !LatteCore.WindowSystem.compositingActive)) || ((root.leftClickAction === LatteTasks.Types.PreviewWindows && !isGroupParent)) ) { activateTask(); } else if (root.leftClickAction === LatteTasks.Types.CycleThroughTasks) { if (isGroupParent) subWindows.activateNextTask(); else activateTask(); } } else { activateTask(); } } backend.cancelHighlightWindows(); } pressed = false; } onWheel: { var wheelActionsEnabled = (root.taskScrollAction !== LatteTasks.Types.ScrollNone || manualScrollTasksEnabled); if (isSeparator || wheelIsBlocked || !wheelActionsEnabled || inBouncingAnimation || (latteView && (latteView.dockIsHidden || latteView.inSlidingIn || latteView.inSlidingOut))){ return; } var angleVertical = wheel.angleDelta.y / 8; var angleHorizontal = wheel.angleDelta.x / 8; wheelIsBlocked = true; scrollDelayer.start(); var verticalDirection = (Math.abs(angleVertical) > Math.abs(angleHorizontal)); var mainAngle = verticalDirection ? angleVertical : angleHorizontal; var positiveDirection = (mainAngle > 12); var negativeDirection = (mainAngle < -12); var parallelScrolling = (verticalDirection && plasmoid.formFactor === PlasmaCore.Types.Vertical) || (!verticalDirection && plasmoid.formFactor === PlasmaCore.Types.Horizontal); if (positiveDirection) { slotPublishGeometries(); var overflowScrollingAccepted = (root.manualScrollTasksEnabled && scrollableList.contentsExceed && (root.manualScrollTasksType === LatteTasks.Types.ManualScrollVerticalHorizontal || (root.manualScrollTasksType === LatteTasks.Types.ManualScrollOnlyParallel && parallelScrolling)) ); if (overflowScrollingAccepted) { scrollableList.decreasePos(); } else { if (isLauncher || root.disableAllWindowsFunctionality) { wrapper.runLauncherAnimation(); } else if (isGroupParent) { subWindows.activateNextTask(); } else { var taskIndex = modelIndex(); if (isMinimized) { tasksModel.requestToggleMinimized(taskIndex); } tasksModel.requestActivate(taskIndex); } // hidePreviewWindow(); } } else if (negativeDirection) { slotPublishGeometries(); var overflowScrollingAccepted = (root.manualScrollTasksEnabled && scrollableList.contentsExceed && (root.manualScrollTasksType === LatteTasks.Types.ManualScrollVerticalHorizontal || (root.manualScrollTasksType === LatteTasks.Types.ManualScrollOnlyParallel && parallelScrolling)) ); if (overflowScrollingAccepted) { scrollableList.increasePos(); } else { if (isLauncher || root.disableAllWindowsFunctionality) { // do nothing } else if (isGroupParent) { if (root.taskScrollAction === LatteTasks.Types.ScrollToggleMinimized) { subWindows.minimizeTask(); } else { subWindows.activatePreviousTask(); } } else { var taskIndex = modelIndex(); var hidingTask = (!isMinimized && root.taskScrollAction === LatteTasks.Types.ScrollToggleMinimized); if (isMinimized || hidingTask) { tasksModel.requestToggleMinimized(taskIndex); } if (!hidingTask) { tasksModel.requestActivate(taskIndex); } } // hidePreviewWindow(); } } } //! A timer is needed in order to handle also touchpads that probably //! send too many signals very fast. This way the signals per sec are limited. //! The user needs to have a steady normal scroll in order to not //! notice a annoying delay Timer{ id: scrollDelayer interval: 400 onTriggered: taskItem.wheelIsBlocked = false; } ///////////////// End Of Mouse Area Events /////////////////// ///// Handlers for Signals ///// function animationStarted(){ // console.log("Animation started: " + index); inAnimation = true; } function animationEnded(){ // console.log("Animation ended: " + index); inAnimation = false; } function sltClearZoom(){ restoreAnimation.start(); } function handlerDraggingFinished(){ isDragged = false; } ///// End of Handlers ////// ///// Helper functions ///// function activateNextTask() { subWindows.activateNextTask(); } function activateTask() { if( taskItem.isLauncher || root.disableAllWindowsFunctionality){ if (LatteCore.WindowSystem.compositingActive) { wrapper.runLauncherAnimation(); } else { launcherAction(); } } else{ if (model.IsGroupParent) { if (LatteCore.WindowSystem.compositingActive && backend.canPresentWindows()) { root.presentWindows(root.plasma515 ? model.WinIdList: model.LegacyWinIdList ); } } else { if (isMinimized) { var i = modelIndex(); tasksModel.requestToggleMinimized(i); tasksModel.requestActivate(i); } else if (isActive) { tasksModel.requestToggleMinimized(modelIndex()); } else { tasksModel.requestActivate(modelIndex()); } } } } function showPreviewWindow() { if (root.disableAllWindowsFunctionality || !isAbleToShowPreview) { return; } if(windowsPreviewDlg.activeItem !== taskItem){ if (!root.latteView || (root.latteView && !root.latteView.isHalfShown && !root.latteView.inSlidingIn && !root.latteView.inSlidingOut)) { if (root.latteView && root.titleTooltips) { root.latteView.hideTooltipLabel(); } taskItem.preparePreviewWindow(false); windowsPreviewDlg.show(taskItem); } } } function showTitleTooltip() { if (root.latteView && root.titleTooltips){ var displayText = isWindow ? model.display : model.AppName; var maxCharacters = 80; var fixedDisplayText = displayText.length>maxCharacters ? displayText.substring(0,maxCharacters-1) + "..." : displayText; root.latteView.showTooltipLabel(taskItem, fixedDisplayText); } } function hidePreviewWindow() { if(windowsPreviewDlg.activeItem === taskItem){ windowsPreviewDlg.hide("14.1"); if (root.latteView && root.titleTooltips && containsMouse) { showTitleTooltip(); } } } function preparePreviewWindow(hideClose){ windowsPreviewDlg.visualParent = previewsVisualParent; toolTipDelegate.parentTask = taskItem; //! WORKAROUND, in order for toolTipDelegate to re-instantiate the previews model when //! previews are changing from single instance preview to another single instance toolTipDelegate.rootIndex = undefined; toolTipDelegate.rootIndex = tasksModel.makeModelIndex(itemIndex, -1); toolTipDelegate.hideCloseButtons = hideClose; toolTipDelegate.appName = Qt.binding(function() { return model.AppName; }); if (!isLauncher) { toolTipDelegate.pidParent = Qt.binding(function() { return model.AppPid; }); } else { toolTipDelegate.pidParent = -1; } toolTipDelegate.windows = Qt.binding(function() { return root.plasma515 ? model.WinIdList : 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.VirtualDesktops !== undefined && model.VirtualDesktops.length > 0) ? model.VirtualDesktops : [0]; }); toolTipDelegate.isOnAllVirtualDesktopsParent = Qt.binding(function() { return model.IsOnAllVirtualDesktops == true; }); toolTipDelegate.activitiesParent = Qt.binding(function() { return model.Activities; }); } function launcherAction(){ // if ((lastButtonClicked == Qt.LeftButton)||(lastButtonClicked == Qt.MidButton)){ if (LatteCore.WindowSystem.compositingActive) { inBouncingAnimation = true; tasksExtendedManager.addWaitingLauncher(taskItem.launcherUrl); } if (root.disableAllWindowsFunctionality) { tasksModel.requestNewInstance(modelIndex()); } else { 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 modelIndex(){ return tasksModel.makeModelIndex(index); } function showContextMenu(args) { if (isSeparator && !root.editMode) return; if (!root.contextMenu) { contextMenu = root.createContextMenu(taskItem, modelIndex(), args); contextMenu.show(); } else { //! make sure that context menu isnt deleted multiple times and creates a crash //! bug case: 397635 var cMenu = root.contextMenu; root.contextMenu = null; cMenu.destroy(); } } function modifierAccepted(mouse){ if (mouse.modifiers & root.modifierQt){ if ((mouse.button === Qt.LeftButton && root.modifierClick === LatteTasks.Types.LeftClick) || (mouse.button === Qt.MiddleButton && root.modifierClick === LatteTasks.Types.MiddleClick) || (mouse.button === Qt.RightButton && root.modifierClick === LatteTasks.Types.RightClick)) return true; } return false; } function setBlockingAnimation(value){ inBlockingAnimation = value; } function slotMimicEnterForParabolic(){ if (containsMouse) { if (inMimicParabolicAnimation) { mimicParabolicScale = taskItem.parabolic.factor.zoom; } wrapper.calculateScales(icList.currentSpot); } } function slotShowPreviewForTasks(group) { if (group === taskItem && !windowsPreviewDlg.visible) { preparePreviewWindow(true); windowsPreviewDlg.show(taskItem); } } function slotPublishGeometries() { //! this way we make sure that layouts that are in different activities that the current layout //! don't publish their geometries if ( canPublishGeometries && (!latteView || root.viewLayoutIsCurrent)) { var globalChoords = backend.globalRect(wrapper.visualIconItem); var limits = backend.globalRect(scrollableList); //! Limit the published geometries boundaries at scrolling area boundaries var adjX = Math.min(limits.x+limits.width, Math.max(limits.x, globalChoords.x)); var adjY = Math.min(limits.y+limits.height, Math.max(limits.y, globalChoords.y)); var length = taskItem.metrics.iconSize * wrapper.mScale; var thickness = length; //! Magic Lamp effect doesn't 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) { if (adjY !== globalChoords.y) { if (((globalChoords.y+globalChoords.height) < limits.y) || (globalChoords.y)>(limits.y+limits.height)) { //! totally out of boundaries length = 4; } else { //! semi-part out of boundaries length = Math.max(4, Math.abs(adjY - globalChoords.y)); } globalChoords.height = length; } } else { if (adjX !== globalChoords.x) { if (((globalChoords.x+globalChoords.width) < limits.x) || (globalChoords.x)>(limits.x+limits.width)) { //! totally out of boundaries length = 4; } else { //! semi-part out of boundaries length = Math.max(4, Math.abs(adjX - globalChoords.x)); } globalChoords.width = length; } } globalChoords.x = adjX; globalChoords.y = adjY; if (latteView && latteView.dockIsHidden) { if (root.location === PlasmaCore.Types.BottomEdge) { globalChoords.y = root.screenGeometry.y+root.screenGeometry.height-1; globalChoords.height = 1; } else if (root.location === PlasmaCore.Types.TopEdge) { globalChoords.y = root.screenGeometry.y+1; globalChoords.height = 1; } else if (root.location === PlasmaCore.Types.LeftEdge) { globalChoords.x = root.screenGeometry.x+1; globalChoords.width = 1; } else if (root.location === PlasmaCore.Types.RightEdge) { globalChoords.x = root.screenGeometry.x+root.screenGeometry.width - 1; globalChoords.width = 1; } } tasksModel.requestPublishDelegateGeometry(taskItem.modelIndex(), globalChoords, taskItem); } } function slotWaitingLauncherRemoved(launch) { if ((isWindow || isStartup || isLauncher) && !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(taskItem.pid); if (streams.length) { pa.registerPidMatch(taskItem.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(taskItem.appName)) { var streams_result; streams_result = pa.streamsForAppName(taskItem.appName); if (streams_result.length===0 && launcherName !== "") { streams_result = pa.streamsForAppName(launcherName); } streams = streams_result; } } // 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){ taskItem.lastValidIndex = taskItem.itemIndex; if (root.showWindowsOnlyFromLaunchers) { parabolicManager.updateTasksEdgesIndexes(); } } if (latteView && latteView.debugModeTimers) { console.log("plasmoid timer: lastValidTimer called..."); } } } ///Item's Removal Animation ListView.onRemove: TaskAnimations.RealRemovalAnimation{ id: taskRealRemovalAnimation } }// main Item