diff --git a/containment/package/contents/ui/applet/AppletItem.qml b/containment/package/contents/ui/applet/AppletItem.qml index 06684b22..5cb195e5 100644 --- a/containment/package/contents/ui/applet/AppletItem.qml +++ b/containment/package/contents/ui/applet/AppletItem.qml @@ -1,856 +1,856 @@ /* * 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.2 as Latte import "../colorizer" as Colorizer import "communicator" as Communicator 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 canShowAppletNumberBadge: !isSeparator && !isHidden && !isLattePlasmoid && !isSpacer && !isInternalViewSplitter 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 isLattePlasmoid: latteApplet !== null property bool isZoomed: false property bool isSeparator: applet && applet.pluginName === "audoban.applet.separator" property bool isSpacer: latteSpacer !== null property bool isSystray: applet && (applet.pluginName === "org.kde.plasma.systemtray" || applet.pluginName === "org.nomad.systemtray" ) 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.Types.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: isSystray ? 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 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) || isSystray) ? wrapper : wrapper.wrapperContainer property Item tooltipVisualParent: titleTooltipParent property alias containsMouse: appletMouseArea.containsMouse property alias pressed: appletMouseArea.pressed /*onComputeHeightChanged: { if(index==0) console.log(computeHeight); }*/ /// 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(container.appletWrapper, mouse.x, mouse.y); if (choords.x<0 || choords.y<0 || choords.x>=container.appletWrapper.width || choords.y>=container.appletWrapper.height) { dock.toggleAppletExpanded(applet.id); } } 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" && (applet.pluginName !== "org.kde.latte.spacer")) && !communicator.canShowOverlaiedLatteIcon) || (isSystray) || (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; } ///END functions //BEGIN connections onAppletChanged: { if (!applet) { destroy(); } } 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; - container.latteApplet.latteDock = root; + container.latteApplet.latteView = root; container.latteApplet.forceHidePanel = true; container.latteApplet.signalAnimationsNeedBothAxis.connect(slotAnimationsNeedBothAxis); container.latteApplet.signalAnimationsNeedLength.connect(slotAnimationsNeedLength); container.latteApplet.signalAnimationsNeedThickness.connect(slotAnimationsNeedThickness); container.latteApplet.signalActionsBlockHiding.connect(slotActionsBlockHiding); container.latteApplet.signalPreviewsShown.connect(slotPreviewsShown); container.latteApplet.clearZoomSignal.connect(titleTooltipDialog.hide); } } 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); if (container.latteApplet) { container.latteApplet.signalAnimationsNeedBothAxis.disconnect(slotAnimationsNeedBothAxis); container.latteApplet.signalAnimationsNeedLength.disconnect(slotAnimationsNeedLength); container.latteApplet.signalAnimationsNeedThickness.disconnect(slotAnimationsNeedThickness); container.latteApplet.signalActionsBlockHiding.disconnect(slotActionsBlockHiding); container.latteApplet.signalPreviewsShown.disconnect(slotPreviewsShown); container.latteApplet.clearZoomSignal.disconnect(titleTooltipDialog.hide); } } Connections{ target: root /* onGlobalDirectRenderChanged:{ if (root.globalDirectRender && restoreAnimation.running) { // console.log("CLEAR APPLET SCALE !!!!"); //restoreAnimation.stop(); //wrapper.zoomScale = 1; } }*/ 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.hasInternalSeparator) { if (index < root.latteAppletPos) { var firstTaskIndex = root.latteApplet.parabolicManager.availableHigherIndex(0); distance = firstTaskIndex+2; } else if (index > root.latteAppletPos) { var lastTaskIndex = root.latteApplet.parabolicManager.availableLowerIndex(root.tasksCount-1); distance = root.tasksCount-1-lastTaskIndex+2; } } if(Math.abs(index-root.latteAppletPos+root.latteAppletHoveredIndex)>=Math.max(2,distance)) { container.clearZoom(); } } } onSignalActivateEntryAtIndex: { if (parabolicManager.pseudoIndexBelongsToLatteApplet(entryIndex) && container.isLattePlasmoid) { latteApplet.activateTaskAtIndex(entryIndex - latteApplet.tasksNumbersBase); } else if (root.unifiedGlobalShortcuts && (entryIndex === parabolicManager.pseudoAppletIndex(container.index))) { dock.toggleAppletExpanded(applet.id); } } onSignalNewInstanceForEntryAtIndex: { if (parabolicManager.pseudoIndexBelongsToLatteApplet(entryIndex) && container.isLattePlasmoid) { latteApplet.newInstanceForTaskAtIndex(entryIndex - latteApplet.tasksNumbersBase); } else if (root.unifiedGlobalShortcuts && (entryIndex === parabolicManager.pseudoAppletIndex(container.index))) { dock.toggleAppletExpanded(applet.id); } } } 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(); if ((restoreAnimation.running) && (layoutsContainer.hoveredIndex !== -1)) { restoreAnimation.stop(); } } } Connections{ target: root onLatteAppletHoveredIndexChanged: { if ((restoreAnimation.running) && (root.latteAppletHoveredIndex !== -1)) { restoreAnimation.stop(); } } } ///END connections //! It is used for any communication needed with the underlying applet Communicator.Engine{ id: communicator //set up the overlaied containers 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; wrapper.disableScaleWidth = false; wrapper.disableScaleHeight = false; wrapper.updateLayoutWidth(); wrapper.updateLayoutHeight(); } 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; } wrapper.disableScaleWidth = false; wrapper.disableScaleHeight = false; wrapper.updateLayoutWidth(); wrapper.updateLayoutHeight(); } } } /* Rectangle{ anchors.fill: parent color: "transparent" border.color: "green" border.width: 1 }*/ MouseArea{ id: appletMouseAreaBottom anchors.fill: parent propagateComposedEvents: true visible: (!appletMouseArea.visible || !appletMouseArea.enabled) && !root.editMode property bool pressed: false onPressed: { container.activateAppletForNeutralAreas(mouse); pressed = true; mouse.accepted = false; } onReleased: { pressed = false; mouse.accepted = false; } } //! Main Applet Shown Area Flow{ id: appletFlow width: container.computeWidth height: container.computeHeight opacity: appletColorizer.mustBeShown ? 0 : 1 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 Behavior on opacity { NumberAnimation { duration: 0.8 * root.animationTime easing.type: Easing.OutCubic } } // a hidden spacer for the first element to add stability // IMPORTANT: hidden spacers must be tested on vertical !!! AppletHiddenSpacer{id: hiddenSpacerLeft} AppletItemWrapper{ id: wrapper TitleTooltipParent{ id: titleTooltipParent } } // a hidden spacer on the right for the last item to add stability AppletHiddenSpacer{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 } //! 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") horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap elide: Text.ElideRight fontSizeMode: Text.Fit color: colorizerManager.applyTheme.textColor rotation: { if (root.isHorizontal) return 0; else if (plasmoid.location === PlasmaCore.Types.LeftEdge) return -90; else if (plasmoid.location === PlasmaCore.Types.RightEdge) return 90; } } } //! The Applet Colorizer Colorizer.Applet { id: appletColorizer anchors.fill: parent opacity: mustBeShown ? 1 : 0 readonly property bool mustBeShown: colorizerManager.mustBeShown && !communicator.disableLatteSideColoring Behavior on opacity { NumberAnimation { duration: 1.2 * root.animationTime easing.type: Easing.OutCubic } } } MouseArea{ id: appletMouseArea anchors.fill: parent enabled: applet && !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: applet && !container.latteApplet && !lockZoom && canBeHovered && !(container.isSeparator && !root.editMode) //&& (root.zoomFactor>1) property bool blockWheel: false property bool pressed: false onClicked: { pressed = false; mouse.accepted = false; } onEntered: { if (containsMouse && !container.lockZoom && container.canBeHovered){ root.stopCheckRestoreZoomTimer(); } if (restoreAnimation.running) { restoreAnimation.stop(); } root.showTooltipLabel(container, applet.title); //console.log("entered applet:" + layoutsContainer.hoveredIndex); if (layoutsContainer.hoveredIndex === -1 && root.latteAppletHoveredIndex===-1) { root.startDirectRenderDelayerDuringEntering(); } if (!(root.dockIsHidden || root.inSlidingIn || root.inSlidingOut)){ layoutsContainer.hoveredIndex = index; } if (lockZoom || !canBeHovered) { 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 (root.zoomFactor>1){ root.startCheckRestoreZoomTimer(); } } onPositionChanged: { // if(!pressed){ if (lockZoom || !canBeHovered) { mouse.accepted = false; return; } if (root.isHalfShown || (root.latteApplet && (root.latteApplet.noTasksInAnimation>0 || root.latteApplet.contextMenu))) { return; } if (layoutsContainer.hoveredIndex === -1 && root.latteAppletHoveredIndex===-1) { root.startDirectRenderDelayerDuringEntering(); } if (!(root.dockIsHidden || root.inSlidingIn || root.inSlidingOut)){ layoutsContainer.hoveredIndex = index; } if (!root.globalDirectRender && !root.directRenderDelayerIsRunning) { root.setGlobalDirectRender(true); } 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 >= root.animationStep){ layoutsContainer.currentSpot = mouse.x; wrapper.calculateScales(mouse.x); } } else{ var step = Math.abs(layoutsContainer.currentSpot-mouse.y); if (step >= root.animationStep){ layoutsContainer.currentSpot = mouse.y; wrapper.calculateScales(mouse.y); } } } mouse.accepted = false; } onPressed: { container.activateAppletForNeutralAreas(mouse); pressed = true; //! this is needed for some applets is order to be activated/deactivated correctly //! such case is the "Application Menu". (bug #928) mouse.accepted = false; } onReleased: { pressed = false; mouse.accepted = false; } onWheel: { if (isSeparator || !root.mouseWheelActions || blockWheel || (root.dockIsHidden || root.inSlidingIn || root.inSlidingOut)){ wheel.accepted = false; return; } var angle = wheel.angleDelta.y / 8; blockWheel = true; scrollDelayer.start(); if (angle > 12) { //positive direction if (!isExpanded) { dock.toggleAppletExpanded(applet.id); } } else if (angle < -12) { //negative direction if (isExpanded) { dock.toggleAppletExpanded(applet.id); } } } //! 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: 700 onTriggered: appletMouseArea.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: 4 * container.animationTime easing.type: Easing.InCubic } PropertyAnimation { target: hiddenSpacerLeft property: "nScale" to: 0 duration: 4 * container.animationTime easing.type: Easing.InCubic } PropertyAnimation { target: hiddenSpacerRight property: "nScale" to: 0 duration: 4 * container.animationTime easing.type: Easing.InCubic } } /////Clicked Animation///// SequentialAnimation{ id: clickedAnimation alwaysRunToEnd: true running: (appletMouseArea.pressed || appletMouseAreaBottom.pressed) && (root.durationTime > 0) onStopped: { appletMouseArea.pressed = false; appletMouseAreaBottom.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/ContextMenu.qml b/plasmoid/package/contents/ui/ContextMenu.qml index 743d7036..a994b248 100644 --- a/plasmoid/package/contents/ui/ContextMenu.qml +++ b/plasmoid/package/contents/ui/ContextMenu.qml @@ -1,908 +1,908 @@ /* * 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 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.activities 0.1 as Activities import org.kde.taskmanager 0.1 as TaskManager import org.kde.latte 0.2 as Latte import "../code/activitiesTools.js" as ActivitiesTools PlasmaComponents.ContextMenu { id: menu property bool changingLayout: false property QtObject mpris2Source property QtObject backend property var modelIndex readonly property var atm: TaskManager.AbstractTasksModel placement: { if (plasmoid.location == PlasmaCore.Types.LeftEdge) { return PlasmaCore.Types.RightPosedTopAlignedPopup; } else if (plasmoid.location == PlasmaCore.Types.TopEdge) { return PlasmaCore.Types.BottomPosedLeftAlignedPopup; } else { return PlasmaCore.Types.TopPosedLeftAlignedPopup; } } minimumWidth: visualParent ? visualParent.width : 1 property bool isOnAllActivitiesLauncher: true property bool showAllPlaces: false property int activitiesCount: 0 onStatusChanged: { if (visualParent && get(atm.LauncherUrlWithoutIcon) != null && status == PlasmaComponents.DialogStatus.Open) { launcherToggleAction.checked = (tasksModel.launcherPosition(get(atm.LauncherUrlWithoutIcon)) != -1); activitiesDesktopsMenu.refresh(); } else if (status == PlasmaComponents.DialogStatus.Closed) { root.startCheckRestoreZoomTimer(100); root.contextMenu = null; menu.destroy(); backend.ungrabMouse(visualParent); } } function get(modelProp) { return tasksModel.data(modelIndex, modelProp) } function show() { //trying to use the dragging mechanism in order to not hide the dock root.disableRestoreZoom = true; root.signalActionsBlockHiding(1); //root.signalDraggingState(true); loadDynamicLaunchActions(visualParent.m.LauncherUrlWithoutIcon); // backend.ungrabMouse(visualParent); openRelative(); if (Latte.WindowSystem.isPlatformWayland){ //!Hiding previews under wayland it needs a delay otherwise it creates crashes windowsPreviewCheckerToNotShowTimer.start(); } else { windowsPreviewDlg.hide("9.4"); } icList.directRender = false; - if (root.latteDock){ - root.latteDock.hideTooltipLabel(); - root.latteDock.globalDirectRender = false; + if (root.latteView){ + root.latteView.hideTooltipLabel(); + root.latteView.globalDirectRender = false; } } function newMenuItem(parent) { return Qt.createQmlObject( "import org.kde.plasma.components 2.0 as PlasmaComponents;" + "PlasmaComponents.MenuItem {}", parent); } function newSeparator(parent) { return Qt.createQmlObject( "import org.kde.plasma.components 2.0 as PlasmaComponents;" + "PlasmaComponents.MenuItem { separator: true }", parent); } function loadDynamicLaunchActions(launcherUrl) { var lists = []; //From Plasma 5.10 and frameworks 5.34, places are also supported if (Latte.WindowSystem.frameworksVersion >= 336384 && (typeof backend.placesActions === "function")) { lists = [ backend.jumpListActions(launcherUrl, menu), backend.placesActions(launcherUrl, showAllPlaces, menu), backend.recentDocumentActions(launcherUrl, menu) ] } else { lists = [ backend.jumpListActions(launcherUrl, menu), backend.recentDocumentActions(launcherUrl, menu) ]; } lists.forEach(function (list) { for (var i = 0; i < list.length; ++i) { var item = newMenuItem(menu); item.action = list[i]; menu.addMenuItem(item, virtualDesktopsMenuItem); } if (list.length > 0) { menu.addMenuItem(newSeparator(menu), virtualDesktopsMenuItem); } }); // Add Media Player control actions var sourceName = mpris2Source.sourceNameForLauncherUrl(launcherUrl, get(atm.AppPid)); if (sourceName && !(get(atm.LegacyWinIdList) != undefined && get(atm.LegacyWinIdList).length > 1)) { var playerData = mpris2Source.data[sourceName] if (playerData.CanControl) { var menuItem = menu.newMenuItem(menu); menuItem.text = i18nc("Play previous track", "Previous Track"); menuItem.icon = "media-skip-backward"; menuItem.enabled = Qt.binding(function() { return playerData.CanGoPrevious; }); menuItem.clicked.connect(function() { mpris2Source.goPrevious(sourceName); }); menu.addMenuItem(menuItem, virtualDesktopsMenuItem); menuItem = menu.newMenuItem(menu); // PlasmaCore Menu doesn't actually handle icons or labels changing at runtime... menuItem.text = Qt.binding(function() { return playerData.PlaybackStatus === "Playing" ? i18nc("Pause playback", "Pause") : i18nc("Start playback", "Play"); }); menuItem.icon = Qt.binding(function() { return playerData.PlaybackStatus === "Playing" ? "media-playback-pause" : "media-playback-start"; }); menuItem.enabled = Qt.binding(function() { return playerData.PlaybackStatus === "Playing" ? playerData.CanPause : playerData.CanPlay; }); menuItem.clicked.connect(function() { mpris2Source.playPause(sourceName); }); menu.addMenuItem(menuItem, virtualDesktopsMenuItem); menuItem = menu.newMenuItem(menu); menuItem.text = i18nc("Play next track", "Next Track"); menuItem.icon = "media-skip-forward"; menuItem.enabled = Qt.binding(function() { return playerData.CanGoNext; }); menuItem.clicked.connect(function() { mpris2Source.goNext(sourceName); }); menu.addMenuItem(menuItem, virtualDesktopsMenuItem); menuItem = menu.newMenuItem(menu); menuItem.text = i18nc("Stop playback", "Stop"); menuItem.icon = "media-playback-stop"; menuItem.clicked.connect(function() { mpris2Source.stop(sourceName); }); menu.addMenuItem(menuItem, virtualDesktopsMenuItem); // Technically media controls and audio streams are separate but for the user they're // semantically related, don't add a separator inbetween. if (!menu.visualParent.hasAudioStream) { menu.addMenuItem(newSeparator(menu), virtualDesktopsMenuItem); } // If we don't have a window associated with the player but we can quit // it through MPRIS we'll offer a "Quit" option instead of "Close" if (!closeWindowItem.visible && playerData.CanQuit) { menuItem = menu.newMenuItem(menu); menuItem.text = i18nc("Quit media player app", "Quit"); menuItem.icon = "application-exit"; menuItem.visible = Qt.binding(function() { return !closeWindowItem.visible; }); menuItem.clicked.connect(function() { mpris2Source.quit(sourceName); }); menu.addMenuItem(menuItem); } // If we don't have a window associated with the player but we can raise // it through MPRIS we'll offer a "Restore" option if (!startNewInstanceItem.visible && playerData.CanRaise) { menuItem = menu.newMenuItem(menu); menuItem.text = i18nc("Open or bring to the front window of media player app", "Restore"); menuItem.icon = playerData["Desktop Icon Name"]; menuItem.visible = Qt.binding(function() { return !startNewInstanceItem.visible; }); menuItem.clicked.connect(function() { mpris2Source.raise(sourceName); }); menu.addMenuItem(menuItem, startNewInstanceItem); } } } // We allow mute/unmute whenever an application has a stream, regardless of whether it // is actually playing sound. // This way you can unmute, e.g. a telephony app, even after the conversation has ended, // so you still have it ringing later on. if (menu.visualParent.hasAudioStream) { var muteItem = menu.newMenuItem(menu); muteItem.checkable = true; muteItem.checked = Qt.binding(function() { return menu.visualParent && menu.visualParent.muted; }); muteItem.clicked.connect(function() { menu.visualParent.toggleMuted(); }); muteItem.text = i18n("Mute"); muteItem.icon = "audio-volume-muted"; menu.addMenuItem(muteItem, virtualDesktopsMenuItem); menu.addMenuItem(newSeparator(menu), virtualDesktopsMenuItem); } } ///REMOVE function updateOnAllActivitiesLauncher(){ //isOnAllActivitiesLauncher = ActivitiesTools.isOnAllActivities(visualParent.m.LauncherUrlWithoutIcon); } Component.onCompleted: { ActivitiesTools.launchersOnActivities = root.launchersOnActivities ActivitiesTools.currentActivity = activityInfo.currentActivity; ActivitiesTools.plasmoid = plasmoid; //From Plasma 5.10 and frameworks 5.34 jumpLists and //places are supported if (Latte.WindowSystem.frameworksVersion >= 336384) { // Cannot have "Connections" as child of PlasmaCoponents.ContextMenu. backend.showAllPlaces.connect(function() { visualParent.showContextMenu({showAllPlaces: true}); }); } // updateOnAllActivitiesLauncher(); } Component.onDestruction: { if (!changingLayout) { root.contextMenu = null; backend.ungrabMouse(visualParent); root.signalActionsBlockHiding(-1); //root.signalDraggingState(false); root.disableRestoreZoom = false; root.startCheckRestoreZoomTimer(100); } } /// Sub Items PlasmaComponents.MenuItem { id: virtualDesktopsMenuItem visible: virtualDesktopInfo.numberOfDesktops > 1 && (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true && visualParent.m.IsVirtualDesktopChangeable === true) enabled: visible text: i18n("Move To Desktop") Connections { target: virtualDesktopInfo onNumberOfDesktopsChanged: virtualDesktopsMenu.refresh() onDesktopNamesChanged: virtualDesktopsMenu.refresh() } PlasmaComponents.ContextMenu { id: virtualDesktopsMenu visualParent: virtualDesktopsMenuItem.action function refresh() { clearMenuItems(); if (virtualDesktopInfo.numberOfDesktops <= 1) { return; } var menuItem = menu.newMenuItem(virtualDesktopsMenu); menuItem.text = i18n("Move To Current Desktop"); menuItem.enabled = Qt.binding(function() { return menu.visualParent && menu.visualParent.m.VirtualDesktop != virtualDesktopInfo.currentDesktop; }); menuItem.clicked.connect(function() { tasksModel.requestVirtualDesktop(menu.modelIndex, 0); }); menuItem = menu.newMenuItem(virtualDesktopsMenu); menuItem.text = i18n("All Desktops"); menuItem.checkable = true; menuItem.checked = Qt.binding(function() { return menu.visualParent && menu.visualParent.m.IsOnAllVirtualDesktops === true; }); menuItem.clicked.connect(function() { tasksModel.requestVirtualDesktop(menu.modelIndex, 0); }); backend.setActionGroup(menuItem.action); menu.newSeparator(virtualDesktopsMenu); for (var i = 0; i < virtualDesktopInfo.desktopNames.length; ++i) { menuItem = menu.newMenuItem(virtualDesktopsMenu); //menuItem.text = i18nc("1 = number of desktop, 2 = desktop name", "%1 Desktop %2", i + 1, virtualDesktopInfo.desktopNames[i]); menuItem.text = (i + 1) + ". " + virtualDesktopInfo.desktopNames[i]; menuItem.checkable = true; menuItem.checked = Qt.binding((function(i) { return function() { return menu.visualParent && menu.visualParent.m.VirtualDesktop == (i + 1) }; })(i)); menuItem.clicked.connect((function(i) { return function() { return tasksModel.requestVirtualDesktop(menu.modelIndex, i + 1); }; })(i)); backend.setActionGroup(menuItem.action); } menu.newSeparator(virtualDesktopsMenu); menuItem = menu.newMenuItem(virtualDesktopsMenu); menuItem.text = i18n("New Desktop"); menuItem.clicked.connect(function() { tasksModel.requestVirtualDesktop(menu.modelIndex, virtualDesktopInfo.numberOfDesktops + 1) }); } Component.onCompleted: refresh() } } PlasmaComponents.MenuItem { id: activitiesDesktopsMenuItem visible: activityInfo.numberOfRunningActivities > 1 && (visualParent && !visualParent.m.IsLauncher && !visualParent.m.IsStartup) && !root.disableAllWindowsFunctionality enabled: visible text: i18n("Move To &Activity") Connections { target: activityInfo onNumberOfRunningActivitiesChanged: activitiesDesktopsMenu.refresh() } PlasmaComponents.ContextMenu { id: activitiesDesktopsMenu visualParent: activitiesDesktopsMenuItem.action function refresh() { clearMenuItems(); if (activityInfo.numberOfRunningActivities <= 1) { return; } var menuItem = menu.newMenuItem(activitiesDesktopsMenu); menuItem.text = i18n("Add To Current Activity"); menuItem.enabled = Qt.binding(function() { return menu.visualParent && menu.visualParent.m.Activities.length > 0 && menu.visualParent.m.Activities.indexOf(activityInfo.currentActivity) < 0; }); menuItem.clicked.connect(function() { tasksModel.requestActivities(menu.modelIndex, menu.visualParent.m.Activities.concat(activityInfo.currentActivity)); }); menuItem = menu.newMenuItem(activitiesDesktopsMenu); menuItem.text = i18n("All Activities"); menuItem.checkable = true; menuItem.checked = Qt.binding(function() { return menu.visualParent && menu.visualParent.m.Activities.length === 0; }); menuItem.clicked.connect(function() { var checked = menuItem.checked; var newActivities = menu.visualParent.m.Activities; var size = newActivities.length; newActivities = undefined; // will cast to an empty QStringList i.e all activities if (size === 0) { newActivities = new Array(activityInfo.currentActivity); } tasksModel.requestActivities(menu.modelIndex, newActivities); }); menu.newSeparator(activitiesDesktopsMenu); var runningActivities = activityInfo.runningActivities(); for (var i = 0; i < runningActivities.length; ++i) { var activityId = runningActivities[i]; menuItem = menu.newMenuItem(activitiesDesktopsMenu); menuItem.text = activityInfo.activityName(runningActivities[i]); menuItem.checkable = true; menuItem.checked = Qt.binding( (function(activityId) { return function() { return menu.visualParent && menu.visualParent.m.Activities.indexOf(activityId) >= 0; }; })(activityId)); menuItem.clicked.connect((function(activityId) { return function () { var checked = menuItem.checked; var newActivities = menu.visualParent.m.Activities; var index = newActivities.indexOf(activityId) if (index < 0) { newActivities = newActivities.concat(activityId); } else { //newActivities = newActivities.splice(index, 1); //this does not work!!! newActivities.splice(index, 1); } return tasksModel.requestActivities(menu.modelIndex, newActivities); }; })(activityId)); } menu.newSeparator(activitiesDesktopsMenu); } Component.onCompleted: refresh() } } PlasmaComponents.MenuItem { visible: (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true && root.showWindowActions && !root.disableAllWindowsFunctionality) enabled: visualParent && visualParent.m.IsMinimizable === true checkable: true checked: visualParent && visualParent.m.IsMinimized === true text: i18n("Minimize") onClicked: tasksModel.requestToggleMinimized(menu.modelIndex) } PlasmaComponents.MenuItem { visible: (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true && root.showWindowActions && !root.disableAllWindowsFunctionality) enabled: visualParent && visualParent.m.IsMaximizable === true checkable: true checked: visualParent && visualParent.m.IsMaximized === true text: i18n("Maximize") onClicked: tasksModel.requestToggleMaximized(menu.modelIndex) } PlasmaComponents.MenuItem { id: moreActionsMenuItem visible: (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true && root.showWindowActions && !root.disableAllWindowsFunctionality) enabled: visible text: i18n("More Actions") PlasmaComponents.ContextMenu { visualParent: moreActionsMenuItem.action PlasmaComponents.MenuItem { enabled: menu.visualParent && menu.visualParent.m.IsMovable === true text: i18n("Move") icon: "transform-move" onClicked: tasksModel.requestMove(menu.modelIndex) } PlasmaComponents.MenuItem { enabled: menu.visualParent && menu.visualParent.m.IsResizable === true text: i18n("Resize") onClicked: tasksModel.requestResize(menu.modelIndex) } PlasmaComponents.MenuItem { checkable: true checked: menu.visualParent && menu.visualParent.m.IsKeepAbove === true text: i18n("Keep Above Others") icon: "go-up" onClicked: tasksModel.requestToggleKeepAbove(menu.modelIndex) } PlasmaComponents.MenuItem { checkable: true checked: menu.visualParent && menu.visualParent.m.IsKeepBelow === true text: i18n("Keep Below Others") icon: "go-down" onClicked: tasksModel.requestToggleKeepBelow(menu.modelIndex) } PlasmaComponents.MenuItem { enabled: menu.visualParent && menu.visualParent.m.IsFullScreenable === true checkable: true checked: menu.visualParent && menu.visualParent.m.IsFullScreen === true text: i18n("Fullscreen") icon: "view-fullscreen" onClicked: tasksModel.requestToggleFullScreen(menu.modelIndex) } PlasmaComponents.MenuItem { enabled: menu.visualParent && menu.visualParent.m.IsShadeable === true checkable: true checked: menu.visualParent && menu.visualParent.m.IsShaded === true text: i18n("Shade") onClicked: tasksModel.requestToggleShaded(menu.modelIndex) } PlasmaComponents.MenuItem { separator: true } PlasmaComponents.MenuItem { visible: (plasmoid.configuration.groupingStrategy != 0) && menu.visualParent.m.IsWindow === true checkable: true checked: menu.visualParent && menu.visualParent.m.IsGroupable === true text: i18n("Allow this program to be grouped") onClicked: tasksModel.requestToggleGrouping(menu.modelIndex) } } } PlasmaComponents.MenuItem { id: startNewInstanceItem visible: (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true) enabled: visualParent && visualParent.m.LauncherUrlWithoutIcon != null text: i18n("Start New Instance") icon: "system-run" onClicked: tasksModel.requestNewInstance(menu.modelIndex) } PlasmaComponents.MenuItem { separator: true visible: (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true && root.showWindowActions) } //// NEW Launchers Mechanism PlasmaComponents.MenuItem { id: launcherToggleAction visible: visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true && (activityInfo.numberOfRunningActivities < 2) //&& plasmoid.immutability !== PlasmaCore.Types.SystemImmutable enabled: visualParent && get(atm.LauncherUrlWithoutIcon) !== "" checkable: true text: i18nc("Toggle action for showing a launcher button while the application is not running", "&Pin") onClicked: { if (tasksModel.launcherPosition(get(atm.LauncherUrlWithoutIcon)) != -1) { var launcher = get(atm.LauncherUrl); - if (latteDock && latteDock.launchersGroup >= Latte.Types.LayoutLaunchers) { - latteDock.universalLayoutManager.launchersSignals.removeLauncher(root.managedLayoutName, - latteDock.launchersGroup, launcher); + if (latteView && latteView.launchersGroup >= Latte.Types.LayoutLaunchers) { + latteView.universalLayoutManager.launchersSignals.removeLauncher(root.managedLayoutName, + latteView.launchersGroup, launcher); } else { root.launcherForRemoval = launcher; tasksModel.requestRemoveLauncher(launcher); root.launchersUpdatedFor(launcher); } } else { var launcher = get(atm.LauncherUrl); - if (latteDock && latteDock.launchersGroup >= Latte.Types.LayoutLaunchers) { - latteDock.universalLayoutManager.launchersSignals.addLauncher(root.managedLayoutName, - latteDock.launchersGroup, launcher); + if (latteView && latteView.launchersGroup >= Latte.Types.LayoutLaunchers) { + latteView.universalLayoutManager.launchersSignals.addLauncher(root.managedLayoutName, + latteView.launchersGroup, launcher); } else { tasksModel.requestAddLauncher(launcher); root.launchersUpdatedFor(launcher); } } } } PlasmaComponents.MenuItem { id: showLauncherInActivitiesItem text: i18n("&Pin") visible: visualParent && (!visualParent.isSeparator || (visualParent.isSeparator && root.editMode)) // && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true && plasmoid.immutability !== PlasmaCore.Types.SystemImmutable && (activityInfo.numberOfRunningActivities >= 2) Connections { target: activityInfo onNumberOfRunningActivitiesChanged: activitiesDesktopsMenu.refresh() } PlasmaComponents.ContextMenu { id: activitiesLaunchersMenu visualParent: showLauncherInActivitiesItem.action function refresh() { clearMenuItems(); if (menu.visualParent === null) return; var createNewItem = function(id, title, url, activities) { var result = menu.newMenuItem(activitiesLaunchersMenu); result.text = title; result.visible = true; result.checkable = true; result.checked = activities.some(function(activity) { return activity === id }); result.clicked.connect( function() { if (result.checked) { - if (latteDock && latteDock.launchersGroup >= Latte.Types.LayoutLaunchers) { - latteDock.universalLayoutManager.launchersSignals.addLauncherToActivity(root.managedLayoutName, - latteDock.launchersGroup, url, id); + if (latteView && latteView.launchersGroup >= Latte.Types.LayoutLaunchers) { + latteView.universalLayoutManager.launchersSignals.addLauncherToActivity(root.managedLayoutName, + latteView.launchersGroup, url, id); } else { if (id !== tasksModel.activity && (activities[0] === "00000000-0000-0000-0000-000000000000")) { root.launcherForRemoval = url; } tasksModel.requestAddLauncherToActivity(url, id); root.launchersUpdatedFor(url); } } else { - if (latteDock && latteDock.launchersGroup >= Latte.Types.LayoutLaunchers) { - latteDock.universalLayoutManager.launchersSignals.removeLauncherFromActivity(root.managedLayoutName, - latteDock.launchersGroup, url, id); + if (latteView && latteView.launchersGroup >= Latte.Types.LayoutLaunchers) { + latteView.universalLayoutManager.launchersSignals.removeLauncherFromActivity(root.managedLayoutName, + latteView.launchersGroup, url, id); } else { if (id === tasksModel.activity) { root.launcherForRemoval = url; } tasksModel.requestRemoveLauncherFromActivity(url, id); root.launchersUpdatedFor(url); } } } ); return result; } if (menu.visualParent === null) return; var url = menu.get(atm.LauncherUrlWithoutIcon); var activities = tasksModel.launcherActivities(url); var NULL_UUID = "00000000-0000-0000-0000-000000000000"; createNewItem(NULL_UUID, i18n("On All Activities"), url, activities); if (activityInfo.numberOfRunningActivities <= 1) { return; } createNewItem(activityInfo.currentActivity, i18n("On The Current Activity"), url, activities); menu.newSeparator(activitiesLaunchersMenu); var runningActivities = activityInfo.runningActivities(); runningActivities.forEach(function(id) { createNewItem(id, activityInfo.activityName(id), url, activities); }); } Component.onCompleted: { menu.onVisualParentChanged.connect(refresh); refresh(); } } } PlasmaComponents.MenuItem { visible: (visualParent && !visualParent.isSeparator && get(atm.IsLauncher) === true) && plasmoid.immutability !== PlasmaCore.Types.SystemImmutable text: i18nc("Remove launcher button for application shown while it is not running", "Unpin") onClicked: { var launcher = get(atm.LauncherUrlWithoutIcon); - if (latteDock && latteDock.launchersGroup >= Latte.Types.LayoutLaunchers) { - latteDock.universalLayoutManager.launchersSignals.removeLauncher(root.managedLayoutName, - latteDock.launchersGroup, launcher); + if (latteView && latteView.launchersGroup >= Latte.Types.LayoutLaunchers) { + latteView.universalLayoutManager.launchersSignals.removeLauncher(root.managedLayoutName, + latteView.launchersGroup, launcher); } else { root.launcherForRemoval = launcher tasksModel.requestRemoveLauncher(launcher); root.launchersUpdatedFor(launcher); } } } //////END OF NEW ARCHITECTURE PlasmaComponents.MenuItem { separator: true } PlasmaComponents.MenuItem { id: addInternalSeparatorItem visible: root.editMode icon: "add" text: i18n("Add Separator") onClicked: { var pos=visualParent.itemIndex; root.addInternalSeparatorAtPos(pos); } } PlasmaComponents.MenuItem { id: removeInternalSeparatorItem visible: root.editMode && visualParent.isSeparator icon: "remove" text: i18n("Remove Separator") enabled: parabolicManager.hasInternalSeparator onClicked: { //root.removeLastSeparator(); var launcher = get(atm.LauncherUrlWithoutIcon); - if (latteDock && latteDock.launchersGroup >= Latte.Types.LayoutLaunchers) { - latteDock.universalLayoutManager.launchersSignals.removeLauncher(root.managedLayoutName, - latteDock.launchersGroup, launcher); + if (latteView && latteView.launchersGroup >= Latte.Types.LayoutLaunchers) { + latteView.universalLayoutManager.launchersSignals.removeLauncher(root.managedLayoutName, + latteView.launchersGroup, launcher); } else { root.launcherForRemoval = launcher; tasksModel.requestRemoveLauncher(launcher); root.launchersUpdatedFor(launcher); } } } PlasmaComponents.MenuItem { separator: true visible: root.editMode } PlasmaComponents.MenuItem { id: layoutsMenuItem - action: latteDock ? latteDock.containmentActions()[1] : plasmoid.action("configure") + action: latteView ? latteView.containmentActions()[1] : plasmoid.action("configure") enabled: visible - visible: latteDock && latteDock.universalLayoutManager.menuLayouts.length>1 + visible: latteView && latteView.universalLayoutManager.menuLayouts.length>1 } PlasmaComponents.MenuItem { id: alternativesMenuItem visible: root.editMode && !visualParent.isSeparator text: plasmoid.action("alternatives").text icon: plasmoid.action("alternatives").icon onClicked: plasmoid.action("alternatives").trigger(); } PlasmaComponents.MenuItem { id: addWidgets - action: latteDock ? latteDock.containmentActions()[2] : plasmoid.action("configure"); - visible: latteDock + action: latteView ? latteView.containmentActions()[2] : plasmoid.action("configure"); + visible: latteView } PlasmaComponents.MenuItem { id: configureItem - action: latteDock ? latteDock.containmentActions()[3] : plasmoid.action("configure") + action: latteView ? latteView.containmentActions()[3] : plasmoid.action("configure") } //! BEGIN: Plasmoid actions when it isnt inside a Latte dock PlasmaComponents.MenuItem { id: removePlasmoid - visible: !latteDock && !plasmoid.immutable + visible: !latteView && !plasmoid.immutable text: plasmoid.action("remove").text icon: plasmoid.action("remove").icon onClicked: plasmoid.action("remove").trigger(); } PlasmaComponents.MenuItem { id: configurePlasmoid - visible: !latteDock && !plasmoid.immutable + visible: !latteView && !plasmoid.immutable text: plasmoid.action("configure").text icon: plasmoid.action("configure").icon onClicked: plasmoid.action("configure").trigger(); } //! END: Plasmoid actions when it isnt inside a Latte dock PlasmaComponents.MenuItem { separator: true visible: closeWindowItem.visible } //!move window Close button at the very bottom in order to not alter users workflow //!comparing with the design decisions of other taskmanagers PlasmaComponents.MenuItem { id: closeWindowItem visible: (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true) enabled: visualParent && visualParent.m.IsClosable === true text: i18n("Close") icon: "window-close" onClicked: { if (root.zoomFactor>1) { delayWindowRemovalTimer.modelIndex = menu.modelIndex; delayWindowRemovalTimer.start(); } else { tasksModel.requestClose(menu.modelIndex); } } } } diff --git a/plasmoid/package/contents/ui/MouseHandler.qml b/plasmoid/package/contents/ui/MouseHandler.qml index aa82254a..c1ef872b 100644 --- a/plasmoid/package/contents/ui/MouseHandler.qml +++ b/plasmoid/package/contents/ui/MouseHandler.qml @@ -1,260 +1,260 @@ /* * 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 org.kde.plasma.plasmoid 2.0 import org.kde.draganddrop 2.0 import org.kde.taskmanager 0.1 as TaskManager import org.kde.latte 0.2 as Latte import "../code/tools.js" as TaskTools Item { // signal urlDropped(url url) signal urlsDropped(var urls) property Item target property Item ignoredItem property bool moved: false property alias hoveredItem: dropHandler.hoveredItem property alias onlyLaunchers: dropHandler.onlyLaunchers Timer { id: ignoreItemTimer repeat: false interval: 200 onTriggered: { ignoredItem = null; } } Connections { target: root onDragSourceChanged: { if (!dragSource) { ignoredItem = null; ignoreItemTimer.stop(); } } } DropArea { id: dropHandler anchors.fill: parent preventStealing: true; property int droppedPosition: -1; property bool onlyLaunchers: false; property bool droppingSeparator: false; property Item hoveredItem function isDroppingSeparator(event) { return ((event.mimeData.formats.indexOf("text/x-plasmoidservicename") === 0) && (String(event.mimeData.getDataAsByteArray("text/x-plasmoidservicename")) === "audoban.applet.separator")); } onDragEnter:{ if(root.dragSource == null){ onlyLaunchers = false; droppingSeparator = false; root.dropNewLauncher = false; var createLaunchers = false; if (event.mimeData.hasUrls || (event.mimeData.formats.indexOf("text/x-plasmoidservicename") !== 0)) { root.dropNewLauncher = true; if (event.mimeData.hasUrls){ createLaunchers = event.mimeData.urls.every(function (item) { return backend.isApplication(item) }); } } else if (isDroppingSeparator(event)) { droppingSeparator = true; root.dropNewLauncher = true; return; } else { event.ignore(); } if (createLaunchers) { onlyLaunchers = true; } } } onDragMove: { /* if(root.dragSource == null){ root.dropNewLauncher = true; } */ if (target.animating) { return; } var above = target.childAtPos(event.x, event.y); // If we're mixing launcher tasks with other tasks and are moving // a (small) launcher task across a non-launcher task, don't allow // the latter to be the move target twice in a row for a while, as // it will naturally be moved underneath the cursor as result of the // initial move, due to being far larger than the launcher delegate. // TODO: This restriction (minus the timer, which improves things) // has been proven out in the EITM fork, but could be improved later // by tracking the cursor movement vector and allowing the drag if // the movement direction has reversed, etablishing user intent to // move back. if (root.dragSource == null && ignoredItem == above) return; if (root.dragSource != null && root.dragSource.m.IsLauncher === true && above != null && above.m != null && above.m.IsLauncher !== true && above == ignoredItem) { return; } else { //ignoredItem = null; } //at some point it was needed the following && above != ignoredItem //but know not... strange... && above != ignoredItem //I use the ignoredItem in order to reduce the move calls as much //as possible if (tasksModel.sortMode == TaskManager.TasksModel.SortManual && root.dragSource && ignoredItem == null) { var insertAt = TaskTools.insertIndexAt(above, event.x, event.y); if (root.dragSource != above && root.dragSource.itemIndex != insertAt) { // console.log(root.dragSource.itemIndex + " - "+insertAt); root.dragSource.z = 100; ignoredItem = above; var pos = root.dragSource.itemIndex; tasksModel.move(pos, insertAt); //! disable syncing for moving launchers action in favor of validatorOrder launchersSignal - /* if (latteDock && latteDock.launchersGroup >= Latte.Types.LayoutLaunchers) { - latteDock.universalLayoutManager.launchersSignals.moveTask(root.managedLayoutName, + /* if (latteView && latteView.launchersGroup >= Latte.Types.LayoutLaunchers) { + latteView.universalLayoutManager.launchersSignals.moveTask(root.managedLayoutName, plasmoid.id, - latteDock.launchersGroup, pos, insertAt); + latteView.launchersGroup, pos, insertAt); }*/ root.separatorsUpdated(); ignoreItemTimer.restart(); } } else if (!root.dragSource && above && hoveredItem != above) { hoveredItem = above; if (!onlyLaunchers) { //! it is needed when dropping a url on a launcher in order to not break parabolic effect root.setHoveredIndex(hoveredItem.itemIndex); } //root.dropNewLauncher = true; activationTimer.restart(); } else if (!above) { //root.dropNewLauncher = true; hoveredItem = null; root.setHoveredIndex(-1); activationTimer.stop(); } if (hoveredItem && windowsPreviewDlg.visible && toolTipDelegate.rootIndex !== hoveredItem.modelIndex() ) { windowsPreviewDlg.hide(6); } } onDragLeave: { hoveredItem = null; root.setHoveredIndex(-1); root.dropNewLauncher = false; onlyLaunchers = false; root.separatorsUpdated(); activationTimer.stop(); } onDrop: { // Reject internal drops. root.dropNewLauncher = false; onlyLaunchers = false; root.separatorsUpdated(); if (event.mimeData.formats.indexOf("application/x-orgkdeplasmataskmanager_taskbuttonitem") >= 0) { return; } if (droppingSeparator) { droppingSeparator = false; if (hoveredItem && hoveredItem.itemIndex >=0){ root.addInternalSeparatorAtPos(hoveredItem.itemIndex); } else { root.addInternalSeparatorAtPos(0); } return; } if (event.mimeData.hasUrls) { parent.urlsDropped(event.mimeData.urls); } } Timer { id: activationTimer interval: 250 repeat: false onTriggered: { if (dropHandler.onlyLaunchers || !root.dropNewLauncher || dropHandler.droppingSeparator) { return; } if (parent.hoveredItem.m.IsGroupParent === true) { root.showPreviewForTasks(parent.hoveredItem); // groupDialog.visualParent = parent.hoveredItem; // groupDialog.visible = true; } else if (parent.hoveredItem.m.IsLauncher !== true) { if(windowsPreviewDlg.visible && toolTipDelegate.currentItem !==parent.hoveredItem.itemIndex ) { windowsPreviewDlg.hide(5); toolTipDelegate.currentItem=-1; } tasksModel.requestActivate(parent.hoveredItem.modelIndex()); } } } } /* MouseArea { id: wheelHandler anchors.fill: parent property int wheelDelta: 0; enabled: plasmoid.configuration.wheelEnabled onWheel: wheelDelta = TaskTools.wheelActivateNextPrevTask(wheelDelta, wheel.angleDelta.y); } */ } diff --git a/plasmoid/package/contents/ui/ParabolicManager.qml b/plasmoid/package/contents/ui/ParabolicManager.qml index 4636a703..1b25f035 100644 --- a/plasmoid/package/contents/ui/ParabolicManager.qml +++ b/plasmoid/package/contents/ui/ParabolicManager.qml @@ -1,555 +1,555 @@ /* * 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 org.kde.plasma.plasmoid 2.0 import org.kde.latte 0.2 as Latte // 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 int firstRealTaskIndex: -1 property int lastRealTaskIndex: -1 property int countRealTasks: -1 //tasks that change state (launcher,startup,window) and //at the next state must look the same //(id, mScale) property variant frozenTasks: [] //new launchers in order to be moved in correct place //(launcher, pos) property variant launchersToBeMoved: [] Connections{ target: root onTasksCountChanged: parManager.updateTasksEdgesIndexes(); onHiddenTasksUpdated: parManager.updateTasksEdgesIndexes(); } Component.onCompleted: { updateHasInternalSeparator(); updateTasksEdgesIndexes(); root.separatorsUpdated.connect(updateHasInternalSeparator); } Component.onDestruction: { root.separatorsUpdated.disconnect(updateHasInternalSeparator); } function updateTasksEdgesIndexes() { var newFirstTask = firstRealTask(); var newLastTask = lastRealTask(); if (newFirstTask !== firstRealTaskIndex || newLastTask !== lastRealTaskIndex ){ firstRealTaskIndex = newFirstTask; lastRealTaskIndex = newLastTask; root.separatorsUpdated(); } countRealTasks = realTasks(); } function updateHasInternalSeparator() { var count = icList.contentItem.children.length; for (var i=0; i=0 && index<=root.tasksCount-1) || (!root.latteDock)){ + if ((index>=0 && index<=root.tasksCount-1) || (!root.latteView)){ root.updateScale(index, zScale, zStep); return -1; } else{ - var appletId = latteDock.latteAppletPos; + var appletId = latteView.latteAppletPos; if (index<0) - appletId = latteDock.parabolicManager.availableLowerId(latteDock.latteAppletPos + index); + appletId = latteView.parabolicManager.availableLowerId(latteView.latteAppletPos + index); else if (index>root.tasksCount-1){ var step=index-root.tasksCount+1; - appletId = latteDock.parabolicManager.availableHigherId(latteDock.latteAppletPos + step); + appletId = latteView.parabolicManager.availableHigherId(latteView.latteAppletPos + step); } - latteDock.updateScale(appletId, zScale, zStep); + latteView.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 ); if (Qt.application.layoutDirection === Qt.RightToLeft && !root.vertical) { positiveDirection = !positiveDirection; } 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; //console.log("--- task style 2..."); var aGId1 = availableHigherIndex(index+1); var aLId1 = availableLowerIndex(index-1); gPAppletId = updateIdSendScale(aGId1, rightScale, 0); lPAppletId = updateIdSendScale(aLId1, leftScale, 0); - // console.log("index:"+index + " lattePos:"+latteDock.latteAppletPos); + // console.log("index:"+index + " lattePos:"+latteView.latteAppletPos); // console.log("gApp:"+gPAppletId+" lApp:"+lPAppletId+ " aG1:"+aGId1+" aLId1:"+aLId1); gStep = aGId1 - index; lStep = index - aLId1; - if (latteDock) { + if (latteView) { if (gPAppletId > -1) - gStep = Math.abs(gPAppletId - latteDock.latteAppletPos + (root.tasksCount-1-index)); + gStep = Math.abs(gPAppletId - latteView.latteAppletPos + (root.tasksCount-1-index)); if (lPAppletId > -1) - lStep = Math.abs(lPAppletId - latteDock.latteAppletPos - index); + lStep = Math.abs(lPAppletId - latteView.latteAppletPos - index); } //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(aGId1+1); clearTasksLowerThan(aLId1-1); - if (latteDock){ + if (latteView){ if (gAppletId > -1) - latteDock.parabolicManager.clearAppletsGreaterThan(gAppletId); + latteView.parabolicManager.clearAppletsGreaterThan(gAppletId); else - latteDock.parabolicManager.clearAppletsGreaterThan(latteDock.latteAppletPos); + latteView.parabolicManager.clearAppletsGreaterThan(latteView.latteAppletPos); if (lAppletId > -1) - latteDock.parabolicManager.clearAppletsLowerThan(lAppletId); + latteView.parabolicManager.clearAppletsLowerThan(lAppletId); else - latteDock.parabolicManager.clearAppletsLowerThan(latteDock.latteAppletPos-1); + latteView.parabolicManager.clearAppletsLowerThan(latteView.latteAppletPos-1); } return {leftScale:leftScale, rightScale:rightScale}; } function clearTasksGreaterThan(index) { if (index0 && root.tasksCount>2) { for(var i=0; i-1 && (hovered === index || hovered === availableLowerIndex(index-1) || hovered === availableHigherIndex(index+1) )) { return true; } return false; } //! Frozen Tasks functions function getFrozenTask(identifier) { for(var i=0; i -1) { frozenTasks.splice(taskIndex, 1); } } function setFrozenTask(identifier, scale) { var frozenTaskExists = false; console.log("SET FROZEN :: "+identifier+" - "+scale); var frozenTask = getFrozenTask(identifier); if (frozenTask) { frozenTask.mScale = scale; } else { frozenTasks.push({id: identifier, mScale: scale}); } } function availableLowerIndex(from) { var next = from; while (next>=0 && (taskIsSeparator(next) || (root.showWindowsOnlyFromLaunchers && taskIsForcedHidden(next))) ) next = next - 1; return next; } function availableHigherIndex(from) { var next = from; while (next<=root.tasksCount-1 && (taskIsSeparator(next) || (root.showWindowsOnlyFromLaunchers && taskIsForcedHidden(next))) ) { next = next + 1; } return next; } function isSeparator(launcher){ return (launcher.indexOf("latte-separator")!==-1 && launcher.indexOf(".desktop")!==1); } function taskIsSeparator(taskIndex){ var task = icList.childAtIndex(taskIndex); return (task && !task.isForcedHidden && task.isSeparator); } function taskIsForcedHidden(taskIndex) { var task = icList.childAtIndex(taskIndex); //!tasks that become hidden there is a chance to have index===-1 and to not be //!able to be tracked down return ((!task && (taskIndex>=0 && taskIndex=0); } //! the real index task after we take into account the separators before it //! for example the first task if there is a separator before it is 1, it isnt 0 function realTaskIndex(pseudoIndex) { if (hasInternalSeparator) { var steps = pseudoIndex + 1; var pos = 0; while (steps > 0) { if (!taskIsSeparator(pos)) { steps = steps - 1; } if (steps > 0) pos = pos + 1; } return pos; } else { return pseudoIndex; } } //! the pseudo index task after we take into account the separators before it //! for example the third task if there is a separator before it is 1, it isnt 2 function pseudoTaskIndex(realIndex) { var pseudoIndex = realIndex; if (hasInternalSeparator) { for (var i=0; i