diff --git a/containment/package/contents/code/AppletIdentifier.js b/containment/package/contents/code/AppletIdentifier.js index 43d9b1d4..7fa41584 100644 --- a/containment/package/contents/code/AppletIdentifier.js +++ b/containment/package/contents/code/AppletIdentifier.js @@ -1,205 +1,205 @@ function typeOf(obj, className){ var name = obj.toString(); //if (applet.pluginName === "org.kde.plasma.kicker") //"set a plugin name to debug" // console.log(name); return ((name.indexOf(className + "(") === 0) || (name.indexOf(className + "_QML") === 0)); } function reconsiderAppletIconItem(){ - if (container.appletIconItem || !applet) + if (container.appletIconItem || !applet || container.disableLatteParabolicIconHeuristics) return; //! searching to find for that applet the first IconItem //! which is going to be used in order to deactivate its active //! from our MouseArea if (applet.pluginName === "org.kde.plasma.kickoff") { identifyKickOff(); } else if (applet.pluginName === "org.kde.plasma.kicker") { identifyKicker(); } else if (applet.pluginName === "org.kde.plasma.simplemenu") { identifySimpleMenu(); } else if (applet.pluginName === "org.kde.plasma.userswitcher"&& !root.behaveAsPlasmaPanel && !container.lockZoom) { identifyUserSwitcher(); } else if (applet.pluginName === "org.kde.comexpertise.plasma.kdeconnect.sms") { identifyKdeConnectSms(); } else if (applet.pluginName === "org.kde.redshiftControl") { //blacklist } else { identifyGeneric(); } } function identifyGeneric() { var level0 = applet.children; for(var i=0; i * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.1 import QtQuick.Layouts 1.1 import QtGraphicalEffects 1.0 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.kquickcontrolsaddons 2.0 import org.kde.latte 0.1 as Latte import "../../code/AppletIdentifier.js" as AppletIndetifier Item { id: container visible: false width: isInternalViewSplitter && !root.editMode ? 0 : (root.isHorizontal ? computeWidth : computeWidth + shownAppletMargin) height: isInternalViewSplitter && !root.editMode ? 0 : (root.isVertical ? computeHeight : computeHeight + shownAppletMargin) property bool animationsEnabled: true property bool animationWasSent: false //protection flag for animation broadcasting property bool canBeHovered: true + property bool disableLatteParabolicIconHeuristics: applet && applet.disableLatteParabolicIcon !== undefined ? applet.disableLatteParabolicIcon : false property bool inFillCalculations: false //temp record, is used in calculations for fillWidth,fillHeight applets property bool needsFillSpace: { //fill flag, it is used in calculations for fillWidth,fillHeight applets if (!applet || !applet.Layout || (applet && applet.pluginName === "org.kde.plasma.panelspacer")) return false; if (((root.isHorizontal && applet.Layout.fillWidth===true) || (root.isVertical && applet.Layout.fillHeight===true)) && (applet.status !== PlasmaCore.Types.HiddenStatus)) return true; else return false; } property bool showZoomed: false property bool lockZoom: false property bool isExpanded: applet && applet.status >= PlasmaCore.Types.NeedsAttentionStatus && applet.status !== PlasmaCore.Types.HiddenStatus property bool isHidden: applet && applet.status === PlasmaCore.Types.HiddenStatus ? true : false property bool isInternalViewSplitter: (internalSplitterId > 0) property bool isZoomed: false property bool isSeparator: applet && applet.pluginName === "audoban.applet.separator" property bool 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.Dock.Justify ? (index === layoutsContainer.mainLayout.beginIndex + layoutsContainer.mainLayout.count - 1)&&(layoutsContainer.mainLayout.count>1) : (((index === layoutsContainer.startLayout.beginIndex+layoutsContainer.startLayout.count-2)&&(layoutsContainer.startLayout.count>2)) ||((index === layoutsContainer.mainLayout.beginIndex+layoutsContainer.mainLayout.count-2)&&(layoutsContainer.mainLayout.count>2)) ||((index === layoutsContainer.endLayout.beginIndex+layoutsContainer.endLayout.count-1)&&(layoutsContainer.endLayout.count>1))) - - + property bool supportsIsInLatte: applet && applet.isInLatte !== undefined ? true : false 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 animationStep: Math.min(3, root.iconSize / 8) property real computeWidth: root.isVertical ? wrapper.width : hiddenSpacerLeft.width+wrapper.width+hiddenSpacerRight.width property real computeHeight: root.isVertical ? hiddenSpacerLeft.height + wrapper.height + hiddenSpacerRight.height : wrapper.height property string title: isInternalViewSplitter ? "Now Dock Splitter" : "" property Item applet: null property Item latteApplet: applet && (applet.pluginName === root.plasmoidName) ? (applet.children[0] ? applet.children[0] : null) : null property Item latteSpacer: applet && (applet.pluginName === "org.kde.latte.spacer") ? (applet.children[0] ? applet.children[0] : null) : null property Item appletWrapper: applet && ((applet.pluginName === root.plasmoidName) || isSystray) ? wrapper : wrapper.wrapperContainer property Item appletIconItem; //first applet's IconItem, to be activated onExit signal property Item appletImageItem; property Item tooltipVisualParent: titleTooltipParent //this is used for folderView and icon widgets to fake their visual property bool fakeIconItem: applet && appletIconItem //(applet.pluginName === "org.kde.plasma.folder" || applet.pluginName === "org.kde.plasma.icon") property alias containsMouse: appletMouseArea.containsMouse property alias pressed: appletMouseArea.pressed /*onComputeHeightChanged: { if(index==0) console.log(computeHeight); }*/ //a timer that is used in order to init the fake applets on startup Timer { id: fakeInitTimer interval: 4000 onTriggered: AppletIndetifier.reconsiderAppletIconItem(); } //set up the fake containers and properties for when a fakeIconItem must be presented to the user //because the plasma widgets specific implementation breaks the Latte experience onFakeIconItemChanged: { if (fakeIconItem) { applet.opacity = 0; if (applet.pluginName === "org.kde.plasma.folder") { applet.parent = wrapper.fakeIconItemContainer; applet.anchors.fill = wrapper.fakeIconItemContainer; } wrapper.disableScaleWidth = false; wrapper.disableScaleHeight = false; wrapper.updateLayoutWidth(); wrapper.updateLayoutHeight(); } } + onDisableLatteParabolicIconHeuristicsChanged: { + if (disableLatteParabolicIconHeuristics && applet.opacity === 0) { + applet.opacity = 1; + + wrapper.disableScaleWidth = false; + wrapper.disableScaleHeight = false; + + wrapper.updateLayoutWidth(); + wrapper.updateLayoutHeight(); + } + } + /// 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") && !container.fakeIconItem) || (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; } function reconsiderAppletIconItem() { AppletIndetifier.reconsiderAppletIconItem(); } ///END functions //BEGIN connections onAppletChanged: { if (!applet) { destroy(); } else { AppletIndetifier.reconsiderAppletIconItem(); fakeInitTimer.start(); } } onHoveredIndexChanged:{ if ( (Math.abs(hoveredIndex-index) > 1) && (hoveredIndex !== -1) ) { wrapper.zoomScale = 1; } if (Math.abs(hoveredIndex-index) >= 1) { hiddenSpacerLeft.nScale = 0; hiddenSpacerRight.nScale = 0; } } onIndexChanged: { if (container.latteApplet) { root.latteAppletPos = index; } if (isHidden) { parabolicManager.setHidden(previousIndex, index); } if (isSeparator) { parabolicManager.setSeparator(previousIndex, index); } if (index>-1) { previousIndex = index; } } onIsExpandedChanged: { if (isExpanded) { root.hideTooltipLabel(); } } onIsHiddenChanged: { if (isHidden) { parabolicManager.setHidden(-1, index); } else { parabolicManager.setHidden(index, -1); } } onIsSeparatorChanged: { if (isSeparator) { parabolicManager.setSeparator(-1, index); } else { parabolicManager.setSeparator(index, -1); } } onLatteAppletChanged: { if(container.latteApplet){ root.latteApplet = container.latteApplet; root.latteAppletContainer = container; root.latteAppletPos = index; container.latteApplet.latteDock = 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; } } + onSupportsIsInLatteChanged: { + if (supportsIsInLatte) { + applet.isInLatte = true; + } + } + 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 onLatteAppletHoveredIndexChanged: { if ( (root.zoomFactor>1) && (root.latteAppletHoveredIndex >= 0) ){ var distance = 2; //for Tasks plasmoid distance of 2 is not always safe there are //cases that needs to be 3, when an internal separator there is //between the hovered task and the current applet if (root.latteInternalSeparatorPos>=0) { if ((index < root.latteAppletPos && root.latteInternalSeparatorPos < root.latteAppletHoveredIndex) || (index > root.latteAppletPos && root.latteInternalSeparatorPos > root.latteAppletHoveredIndex)) { distance = 3; } } if(Math.abs(index-root.latteAppletPos+root.latteAppletHoveredIndex)>=distance) { container.clearZoom(); } } } } Connections{ target: layoutsContainer onHoveredIndexChanged:{ //for applets it is safe to consider that a distance of 2 //is enough to clearZoom if ( (root.zoomFactor>1) && (layoutsContainer.hoveredIndex>=0) && (Math.abs(index-layoutsContainer.hoveredIndex)>=2)) container.clearZoom(); } } ///END connections PlasmaComponents.BusyIndicator { z: 1000 visible: applet && applet.busy running: visible anchors.centerIn: parent width: Math.min(parent.width, parent.height) height: width } /* Rectangle{ anchors.fill: parent color: "transparent" border.color: "green" border.width: 1 }*/ MouseArea{ id: appletMouseAreaBottom anchors.fill: parent propagateComposedEvents: true visible: !appletMouseArea.visible && !root.editMode onPressed: { container.activateAppletForNeutralAreas(mouse); mouse.accepted = false; } } Flow{ id: appletFlow width: container.computeWidth height: container.computeHeight anchors.rightMargin: (latteApplet || (showZoomed && root.editMode)) || (plasmoid.location !== PlasmaCore.Types.RightEdge) ? 0 : shownAppletMargin anchors.leftMargin: (latteApplet || (showZoomed && root.editMode)) || (plasmoid.location !== PlasmaCore.Types.LeftEdge) ? 0 : shownAppletMargin anchors.topMargin: (latteApplet || (showZoomed && root.editMode)) || (plasmoid.location !== PlasmaCore.Types.TopEdge)? 0 : shownAppletMargin anchors.bottomMargin: (latteApplet || (showZoomed && root.editMode)) || (plasmoid.location !== PlasmaCore.Types.BottomEdge) ? 0 : shownAppletMargin // a hidden spacer for the first element to add stability // IMPORTANT: hidden spacers must be tested on vertical !!! Item{ id: hiddenSpacerLeft //we add one missing pixel from calculations width: root.isHorizontal ? nHiddenSize : wrapper.width height: root.isHorizontal ? wrapper.height : nHiddenSize ///check also if this is the first plasmoid in anylayout visible: container.startEdge || separatorSpace>0 property bool neighbourSeparator: false; //in case there is a neighbour internal separator property int separatorSpace: ((root.latteApplet && root.latteApplet.hasInternalSeparator && !root.latteApplet.internalSeparatorHidden && (root.latteApplet.internalSeparatorPos === root.tasksCount-1) && index===root.latteAppletPos+1) || neighbourSeparator) && !container.isSeparator && !container.latteApplet ? (2+root.iconMargin/2) : 0 property real nHiddenSize: (nScale > 0) ? (container.spacersMaxSize * nScale) + separatorSpace : separatorSpace property real nScale: 0 Behavior on nScale { enabled: !root.globalDirectRender NumberAnimation { duration: 3*container.animationTime } } Behavior on nScale { enabled: root.globalDirectRender NumberAnimation { duration: root.directRenderAnimationTime } } Connections{ target: root onSeparatorsUpdated: { hiddenSpacerLeft.neighbourSeparator = parabolicManager.isSeparator(index-1); } } Loader{ width: !root.isVertical ? parent.width : 1 height: !root.isVertical ? 1 : parent.height x: root.isVertical ? parent.width /2 : 0 y: !root.isVertical ? parent.height /2 : 0 active: root.debugMode sourceComponent: Rectangle{ border.width: 1 border.color: "red" color: "transparent" } } } AppletItemWrapper{ id: wrapper TitleTooltipParent{ id: titleTooltipParent } } // a hidden spacer on the right for the last item to add stability Item{ id: hiddenSpacerRight //we add one missing pixel from calculations width: root.isHorizontal ? nHiddenSize : wrapper.width height: root.isHorizontal ? wrapper.height : nHiddenSize //check if this last plasmoid in any layout visible: container.endEdge || separatorSpace>0 property bool neighbourSeparator: false; //in case there is a neighbour internal separator property int separatorSpace: ((root.latteApplet && root.latteApplet.hasInternalSeparator && !root.latteApplet.internalSeparatorHidden && root.latteApplet.internalSeparatorPos === 0 && index===root.latteAppletPos-1) || neighbourSeparator) && !container.isSeparator && !container.latteApplet ? (2+root.iconMargin/2) : 0 property real nHiddenSize: (nScale > 0) ? (container.spacersMaxSize * nScale) + separatorSpace : separatorSpace property real nScale: 0 Behavior on nScale { enabled: !root.globalDirectRender NumberAnimation { duration: 3*container.animationTime } } Behavior on nScale { enabled: root.globalDirectRender NumberAnimation { duration: root.directRenderAnimationTime } } Connections{ target: root onSeparatorsUpdated: { hiddenSpacerRight.neighbourSeparator = parabolicManager.isSeparator(index+1); } } Loader{ width: !root.isVertical ? parent.width : 1 height: !root.isVertical ? 1 : parent.height x: root.isVertical ? parent.width /2 : 0 y: !root.isVertical ? parent.height /2 : 0 active: root.debugMode sourceComponent: Rectangle{ border.width: 1 border.color: "red" color: "transparent" } } } }// Flow with hidden spacers inside //! The Launchers Area Indicator Rectangle{ anchors.fill: parent radius: root.iconSize/10 property color tempColor: "#aa222222" color: tempColor border.width: 1 border.color: "#ff656565" opacity: latteApplet && root.addLaunchersMessage ? 1 : 0 Behavior on opacity{ NumberAnimation { duration: 2*root.durationTime*container.animationTime } } PlasmaExtras.Heading { width: parent.width height: parent.height text: i18n("Launchers Area") level: 3 font.bold: true horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap elide: Text.ElideRight rotation: { if (root.isHorizontal) return 0; else if (plasmoid.location === PlasmaCore.Types.LeftEdge) return -90; else if (plasmoid.location === PlasmaCore.Types.RightEdge) return 90; } } } MouseArea{ id: appletMouseArea anchors.fill: parent enabled: (!latteApplet)&&(canBeHovered)&&(!root.editMode)//&&(!lockZoom) hoverEnabled: !root.editMode && (!latteApplet) ? true : false propagateComposedEvents: true //! a way must be found in order for this be enabled //! only to support springloading for plasma 5.10 //! also on this is based the tooltips behavior by enabling it //! plasma tooltips are disabled visible: !container.latteApplet && !lockZoom && canBeHovered && !(container.isSeparator && !root.editMode) //&& (root.zoomFactor>1) property bool pressed: false onClicked: { pressed = false; mouse.accepted = false; } onEntered: { //AppletIndetifier.reconsiderAppletIconItem(); root.showTooltipLabel(container, applet.title); if (lockZoom || !canBeHovered) { return; } layoutsContainer.hoveredIndex = index; if (root.isHalfShown || (root.latteApplet && root.latteApplet.noTasksInAnimation>0)) { return; } if (root.isHorizontal){ layoutsContainer.currentSpot = mouseX; wrapper.calculateScales(mouseX); } else{ layoutsContainer.currentSpot = mouseY; wrapper.calculateScales(mouseY); } } onExited:{ if (appletIconItem && appletIconItem.visible) appletIconItem.active = false; root.hideTooltipLabel(); if (root.zoomFactor>1){ checkRestoreZoom.start(); } } onPositionChanged: { // if(!pressed){ if (lockZoom || !canBeHovered) { mouse.accepted = false; return; } if (root.isHalfShown || (root.latteApplet && root.latteApplet.noTasksInAnimation>0)) { return; } if( ((wrapper.zoomScale == 1 || wrapper.zoomScale === root.zoomFactor) && !root.globalDirectRender) || root.globalDirectRender) { if (root.isHorizontal){ var step = Math.abs(layoutsContainer.currentSpot-mouse.x); if (step >= container.animationStep){ layoutsContainer.hoveredIndex = index; layoutsContainer.currentSpot = mouse.x; wrapper.calculateScales(mouse.x); } } else{ var step = Math.abs(layoutsContainer.currentSpot-mouse.y); if (step >= container.animationStep){ layoutsContainer.hoveredIndex = index; layoutsContainer.currentSpot = mouse.y; wrapper.calculateScales(mouse.y); } } } mouse.accepted = false; } onPressed: { container.activateAppletForNeutralAreas(mouse); pressed = true; mouse.accepted = false; } onReleased: { pressed = false; } } //BEGIN states states: [ State { name: "left" when: (plasmoid.location === PlasmaCore.Types.LeftEdge) AnchorChanges { target: appletFlow anchors{ top:undefined; bottom:undefined; left:parent.left; right:undefined;} } }, State { name: "right" when: (plasmoid.location === PlasmaCore.Types.RightEdge) AnchorChanges { target: appletFlow anchors{ top:undefined; bottom:undefined; left:undefined; right:parent.right;} } }, State { name: "bottom" when: (plasmoid.location === PlasmaCore.Types.BottomEdge) AnchorChanges { target: appletFlow anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:undefined;} } }, State { name: "top" when: (plasmoid.location === PlasmaCore.Types.TopEdge) AnchorChanges { target: appletFlow anchors{ top:parent.top; bottom:undefined; left:undefined; right:undefined;} } } ] //END states //BEGIN animations ///////Restore Zoom Animation///// ParallelAnimation{ id: restoreAnimation PropertyAnimation { target: wrapper property: "zoomScale" to: 1 duration: 3 * container.animationTime easing.type: Easing.Linear } PropertyAnimation { target: hiddenSpacerLeft property: "nScale" to: 0 duration: 3 * container.animationTime easing.type: Easing.Linear } PropertyAnimation { target: hiddenSpacerRight property: "nScale" to: 0 duration: 3 * container.animationTime easing.type: Easing.Linear } } /////Clicked Animation///// SequentialAnimation{ id: clickedAnimation alwaysRunToEnd: true running: appletMouseArea.pressed && (root.durationTime > 0) onStopped: appletMouseArea.pressed = false; ParallelAnimation{ PropertyAnimation { target: wrapper.clickedEffect property: "brightness" to: -0.35 duration: units.longDuration easing.type: Easing.OutQuad } } ParallelAnimation{ PropertyAnimation { target: wrapper.clickedEffect property: "brightness" to: 0 duration: units.longDuration easing.type: Easing.OutQuad } } } //END animations } diff --git a/containment/package/contents/ui/applet/AppletItemWrapper.qml b/containment/package/contents/ui/applet/AppletItemWrapper.qml index 890c9318..aeb3aacf 100644 --- a/containment/package/contents/ui/applet/AppletItemWrapper.qml +++ b/containment/package/contents/ui/applet/AppletItemWrapper.qml @@ -1,693 +1,693 @@ /* * 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.latte 0.1 as Latte Item{ id: wrapper width: { if (container.isInternalViewSplitter && !root.editMode) return 0; if (container.isSeparator && !root.editMode) { if (!root.isVertical) return -1; else return root.iconSize; } if (container.needsFillSpace && (container.sizeForFill>-1) && root.isHorizontal){ //! in edit mode shrink a bit the fill sizes because the splitters are shown return root.editMode && container.needsFillSpace && (container.sizeForFill > 5*root.iconSize) ? container.sizeForFill - 2.5*root.iconSize : container.sizeForFill; //return container.sizeForFill; } if (container.latteApplet) { if (container.showZoomed && root.isVertical) return root.statesLineSize + root.thickMargin + root.iconSize + 1; else return latteApplet.tasksWidth; } else { return scaledWidth; } } height: { if (container.isInternalViewSplitter && !root.editMode) return 0; if (container.isSeparator && !root.editMode) { if (root.isVertical) return -1; else return root.iconSize; } if (container.needsFillSpace && (container.sizeForFill>-1) && root.isVertical){ //! in edit mode shrink a bit the fill sizes because the splitters are shown return root.editMode && container.needsFillSpace && (container.sizeForFill > 5*root.iconSize) ? container.sizeForFill - 2.5*root.iconSize : container.sizeForFill; //return container.sizeForFill; } if (container.latteApplet) { if (container.showZoomed && root.isHorizontal) return root.statesLineSize + root.thickMargin + root.iconSize + 1; else return latteApplet.tasksHeight; } else { return scaledHeight; } } //width: container.isInternalViewSplitter && !root.editMode ? 0 : Math.round( latteApplet ? ((container.showZoomed && root.isVertical) ? // scaledWidth : latteApplet.tasksWidth) : scaledWidth ) //height: container.isInternalViewSplitter&& !root.editMode ? 0 : Math.round( latteApplet ? ((container.showZoomed && root.isHorizontal) ? // scaledHeight : latteApplet.tasksHeight ): scaledHeight ) property bool disableScaleWidth: false property bool disableScaleHeight: false property bool editMode: root.editMode property int appletMinimumWidth: applet && applet.Layout ? applet.Layout.minimumWidth : -1 property int appletMinimumHeight: applet && applet.Layout ? applet.Layout.minimumHeight : -1 property int appletPreferredWidth: applet && applet.Layout ? applet.Layout.preferredWidth : -1 property int appletPreferredHeight: applet && applet.Layout ? applet.Layout.preferredHeight : -1 property int appletMaximumWidth: applet && applet.Layout ? applet.Layout.maximumWidth : -1 property int appletMaximumHeight: applet && applet.Layout ? applet.Layout.maximumHeight : -1 property int iconSize: root.iconSize property int marginWidth: root.isVertical ? (container.isSystray ? root.thickMarginBase : root.thickMargin ) : (root.inFullJustify && (container.firstChildOfStartLayout || container.lastChildOfEndLayout ) ? 0 : root.iconMargin) //Fitt's Law property int marginHeight: root.isHorizontal ? (container.isSystray ? root.thickMarginBase : root.thickMargin ) : (root.inFullJustify && (container.firstChildOfStartLayout || container.lastChildOfEndLayout ) ? 0 : root.iconMargin) //Fitt's Law property real scaledWidth: zoomScaleWidth * (layoutWidth + marginWidth) property real scaledHeight: zoomScaleHeight * (layoutHeight + marginHeight) property real zoomScaleWidth: disableScaleWidth ? 1 : zoomScale property real zoomScaleHeight: disableScaleHeight ? 1 : zoomScale property int layoutWidthResult: 0 property int layoutWidth property int layoutHeight // property int localMoreSpace: root.reverseLinesPosition ? root.statesLineSize + 2 : appletMargin property int localMoreSpace: appletMargin property int moreHeight: (container.isSystray || root.reverseLinesPosition) && root.isHorizontal ? localMoreSpace : 0 property int moreWidth: (container.isSystray || root.reverseLinesPosition) && root.isVertical ? localMoreSpace : 0 property real center:(width + hiddenSpacerLeft.separatorSpace + hiddenSpacerRight.separatorSpace) / 2 property real zoomScale: 1 property int index: container.index property Item wrapperContainer: _wrapperContainer property Item clickedEffect: _clickedEffect property Item fakeIconItemContainer: _fakeIconItemContainer // property int pHeight: applet ? applet.Layout.preferredHeight : -10 /*function debugLayouts(){ if(applet){ console.log("---------- "+ applet.pluginName +" ----------"); console.log("MinW "+applet.Layout.minimumWidth); console.log("PW "+applet.Layout.preferredWidth); console.log("MaxW "+applet.Layout.maximumWidth); console.log("FillW "+applet.Layout.fillWidth); console.log("-----"); console.log("MinH "+applet.Layout.minimumHeight); console.log("PH "+applet.Layout.preferredHeight); console.log("MaxH "+applet.Layout.maximumHeight); console.log("FillH "+applet.Layout.fillHeight); console.log("-----"); console.log("LayoutW: " + layoutWidth); console.log("LayoutH: " + layoutHeight); } } onLayoutWidthChanged: { debugLayouts(); } onLayoutHeightChanged: { debugLayouts(); }*/ onAppletMinimumWidthChanged: { if(zoomScale == 1) checkCanBeHovered(); updateLayoutWidth(); } onAppletMinimumHeightChanged: { if(zoomScale == 1) checkCanBeHovered(); updateLayoutHeight(); } onAppletPreferredWidthChanged: updateLayoutWidth(); onAppletPreferredHeightChanged: updateLayoutHeight(); onAppletMaximumWidthChanged: updateLayoutWidth(); onAppletMaximumHeightChanged: updateLayoutHeight(); onIconSizeChanged: { updateLayoutWidth(); updateLayoutHeight(); } onEditModeChanged: { updateLayoutWidth(); updateLayoutHeight(); } onZoomScaleChanged: { if ((zoomScale === root.zoomFactor) && !enableDirectRenderTimer.running && !root.globalDirectRender) { root.setGlobalDirectRender(true); enableDirectRenderTimer.start(); } if ((zoomScale > 1) && !container.isZoomed) { container.isZoomed = true; if (!root.editMode && !animationWasSent) { root.slotAnimationsNeedBothAxis(1); animationWasSent = true; } } else if ((zoomScale == 1) && container.isZoomed) { container.isZoomed = false; if (animationWasSent) { root.slotAnimationsNeedBothAxis(-1); animationWasSent = false; } } } Connections { target: root onIsVerticalChanged: { if (container.latteApplet) { return; } wrapper.disableScaleWidth = false; wrapper.disableScaleHeight = false; if (root.isVertical) { wrapper.updateLayoutHeight(); wrapper.updateLayoutWidth(); } else { wrapper.updateLayoutWidth(); wrapper.updateLayoutHeight(); } } } function updateLayoutHeight(){ if(container.isInternalViewSplitter){ if(!root.editMode) layoutHeight = 0; else layoutHeight = root.iconSize;// + moreHeight + root.statesLineSize; } else if(applet && applet.pluginName === "org.kde.plasma.panelspacer"){ layoutHeight = root.iconSize + moreHeight; } else if(container.isSystray && root.isHorizontal){ layoutHeight = root.statesLineSize + root.iconSize; } else{ if(applet && (applet.Layout.minimumHeight > root.iconSize) && root.isVertical && !canBeHovered && !container.fakeIconItem){ // return applet.Layout.minimumHeight; layoutHeight = applet.Layout.minimumHeight; } //it is used for plasmoids that need to scale only one axis... e.g. the Weather Plasmoid else if(applet && ( (applet.Layout.maximumHeight < root.iconSize) || (applet.Layout.preferredHeight > root.iconSize)) && root.isVertical && !disableScaleWidth && !container.fakeIconItem) { //&& !root.editMode ){ disableScaleHeight = true; //this way improves performance, probably because during animation the preferred sizes update a lot if((applet.Layout.maximumHeight < root.iconSize)){ layoutHeight = applet.Layout.maximumHeight; } else if (applet.Layout.minimumHeight > root.iconSize){ layoutHeight = applet.Layout.minimumHeight; } else if ((applet.Layout.preferredHeight > root.iconSize)){ layoutHeight = applet.Layout.preferredHeight; } else{ layoutHeight = root.iconSize + moreHeight; } } else layoutHeight = root.iconSize + moreHeight; } //return root.iconSize + moreHeight; } function updateLayoutWidth(){ if(container.isInternalViewSplitter){ if(!root.editMode) layoutWidth = 0; else layoutWidth = root.iconSize; //+ moreWidth+ root.statesLineSize; } else if(applet && applet.pluginName === "org.kde.plasma.panelspacer"){ layoutWidth = root.iconSize + moreWidth; } else if(container.isSystray && root.isVertical){ layoutWidth = root.statesLineSize + root.iconSize; } else{ if(applet && (applet.Layout.minimumWidth > root.iconSize) && root.isHorizontal && !canBeHovered && !container.fakeIconItem){ layoutWidth = applet.Layout.minimumWidth; } //it is used for plasmoids that need to scale only one axis... e.g. the Weather Plasmoid else if(applet && ( (applet.Layout.maximumWidth < root.iconSize) || (applet.Layout.preferredWidth > root.iconSize)) && root.isHorizontal && !disableScaleHeight && !container.fakeIconItem){ // && !root.editMode){ disableScaleWidth = true; //this way improves performance, probably because during animation the preferred sizes update a lot if((applet.Layout.maximumWidth < root.iconSize)){ // return applet.Layout.maximumWidth; layoutWidth = applet.Layout.maximumWidth; } else if (applet.Layout.minimumWidth > root.iconSize){ layoutWidth = applet.Layout.minimumWidth; } else if (applet.Layout.preferredWidth > root.iconSize){ layoutWidth = applet.Layout.preferredWidth; } else{ layoutWidth = root.iconSize + moreWidth; } } else{ //return root.iconSize + moreWidth; layoutWidth = root.iconSize + moreWidth; } } } Loader{ anchors.fill: parent active: root.activeIndicator === Latte.Dock.AllIndicator || (root.activeIndicator === Latte.Dock.InternalsIndicator && fakeIconItem) sourceComponent: Item{ anchors.fill: parent ActiveIndicator{} } } Item{ id:_wrapperContainer width:{ if (container.needsFillSpace && (container.sizeForFill>-1) && root.isHorizontal){ return wrapper.width; } if (container.isInternalViewSplitter) return wrapper.layoutWidth; else return parent.zoomScaleWidth * wrapper.layoutWidth; } height:{ if (container.needsFillSpace && (container.sizeForFill>-1) && root.isVertical){ return wrapper.height; } if (container.isInternalViewSplitter) return wrapper.layoutHeight; else return parent.zoomScaleHeight * wrapper.layoutHeight; } //width: Math.round( container.isInternalViewSplitter ? wrapper.layoutWidth : parent.zoomScaleWidth * wrapper.layoutWidth ) //height: Math.round( container.isInternalViewSplitter ? wrapper.layoutHeight : parent.zoomScaleHeight * wrapper.layoutHeight ) anchors.rightMargin: plasmoid.location === PlasmaCore.Types.RightEdge ? lowThickUsed : 0 anchors.leftMargin: plasmoid.location === PlasmaCore.Types.LeftEdge ? lowThickUsed : 0 anchors.topMargin: plasmoid.location === PlasmaCore.Types.TopEdge ? lowThickUsed : 0 anchors.bottomMargin: plasmoid.location === PlasmaCore.Types.BottomEdge ? lowThickUsed : 0 opacity: appletShadow.active ? 0 : 1 property int lowThickUsed: root.reverseLinesPosition ? root.thickMarginHigh : root.thickMarginBase //BEGIN states states: [ State { name: "left" when: (plasmoid.location === PlasmaCore.Types.LeftEdge) AnchorChanges { target: _wrapperContainer anchors{ verticalCenter:wrapper.verticalCenter; horizontalCenter:undefined; top:undefined; bottom:undefined; left:parent.left; right:undefined;} } }, State { name: "right" when: (plasmoid.location === PlasmaCore.Types.RightEdge) AnchorChanges { target: _wrapperContainer anchors{ verticalCenter:wrapper.verticalCenter; horizontalCenter:undefined; top:undefined; bottom:undefined; left:undefined; right:parent.right;} } }, State { name: "bottom" when: (plasmoid.location === PlasmaCore.Types.BottomEdge) AnchorChanges { target: _wrapperContainer anchors{ verticalCenter:undefined; horizontalCenter:wrapper.horizontalCenter; top:undefined; bottom:parent.bottom; left:undefined; right:undefined;} } }, State { name: "top" when: (plasmoid.location === PlasmaCore.Types.TopEdge) AnchorChanges { target: _wrapperContainer anchors{ verticalCenter:undefined; horizontalCenter:wrapper.horizontalCenter; top:parent.top; bottom:undefined; left:undefined; right:undefined;} } } ] //END states ///Secret MouseArea to be used by the folder widget Loader{ anchors.fill: parent - active: container.fakeIconItem && applet.pluginName === "org.kde.plasma.folder" + active: container.fakeIconItem && applet.pluginName === "org.kde.plasma.folder" && !container.disableLatteParabolicIconHeuristics sourceComponent: MouseArea{ onClicked: dock.toggleAppletExpanded(applet.id); } } Item{ id: _fakeIconItemContainer anchors.centerIn: parent //we setup as maximum for hidden container of some applets that break //the Latte experience the size:96 . This is why after that size //the folder widget changes to fullRepresentation instead of compact one width: Math.min(96, parent.width) height: width } Loader{ anchors.fill: parent - active: container.fakeIconItem + active: container.fakeIconItem && !container.disableLatteParabolicIconHeuristics sourceComponent: Latte.IconItem{ id: fakeAppletIconItem anchors.fill: parent source: { if (appletIconItem && appletIconItem.visible) return appletIconItem.source; else if (appletImageItem && appletImageItem.visible) return appletImageItem.source; } usesPlasmaTheme: appletIconItem && appletIconItem.visible ? appletIconItem.usesPlasmaTheme : false //ActiveIndicator{} } } } //spacer background Loader{ anchors.fill: _wrapperContainer active: applet && (applet.pluginName === "org.kde.plasma.panelspacer") && root.editMode sourceComponent: Rectangle{ anchors.fill: parent border.width: 1 border.color: theme.textColor color: "transparent" opacity: 0.7 radius: root.iconMargin Rectangle{ anchors.centerIn: parent color: parent.border.color width: parent.width - 1 height: parent.height - 1 opacity: 0.2 } } } Loader{ anchors.fill: _wrapperContainer active: container.isInternalViewSplitter && root.editMode rotation: root.isVertical ? 90 : 0 sourceComponent: Image{ id:splitterImage anchors.fill: parent source: (container.internalSplitterId===1) ? "../../icons/splitter.png" : "../../icons/splitter2.png" layer.enabled: true layer.effect: DropShadow { radius: root.appShadowSize samples: 2 * radius color: root.appShadowColor verticalOffset: 2 } Component.onCompleted: wrapper.zoomScale = 1.1 } } ///Shadow in applets Loader{ id: appletShadow anchors.fill: container.appletWrapper active: container.applet && (((plasmoid.configuration.shadows === 1 /*Locked Applets*/ && (!container.canBeHovered || (container.lockZoom && (applet.pluginName !== root.plasmoidName))) ) || (plasmoid.configuration.shadows === 2 /*All Applets*/ && (applet.pluginName !== root.plasmoidName))) || (root.forceTransparentPanel && plasmoid.configuration.shadows>0 && applet.pluginName !== root.plasmoidName)) /*on forced transparent state*/ onActiveChanged: { if (active) { wrapperContainer.opacity = 0; } else { wrapperContainer.opacity = 1; } } sourceComponent: DropShadow{ anchors.fill: parent color: root.appShadowColor //"#ff080808" samples: 2 * radius source: container.fakeIconItem ? _wrapperContainer : container.applet radius: shadowSize verticalOffset: forcedShadow ? 1 : 2 property int shadowSize : forcedShadow? 8 : root.appShadowSize //Math.ceil(root.iconSize / 12) property bool forcedShadow: root.forceTransparentPanel && plasmoid.configuration.shadows>0 && applet.pluginName !== root.plasmoidName ? true : false } } BrightnessContrast{ id:hoveredImage anchors.fill: _wrapperContainer source: _wrapperContainer enabled: opacity != 0 ? true : false opacity: appletMouseArea.containsMouse ? 1 : 0 brightness: 0.25 contrast: 0.15 Behavior on opacity { NumberAnimation { duration: root.durationTime*units.longDuration } } } BrightnessContrast { id: _clickedEffect anchors.fill: _wrapperContainer source: _wrapperContainer visible: clickedAnimation.running } /* onHeightChanged: { if ((index == 1)|| (index==3)){ console.log("H: "+index+" ("+zoomScale+"). "+currentLayout.children[1].height+" - "+currentLayout.children[3].height+" - "+(currentLayout.children[1].height+currentLayout.children[3].height)); } } onZoomScaleChanged:{ if ((index == 1)|| (index==3)){ console.log(index+" ("+zoomScale+"). "+currentLayout.children[1].height+" - "+currentLayout.children[3].height+" - "+(currentLayout.children[1].height+currentLayout.children[3].height)); } }*/ Loader{ anchors.fill: parent active: root.debugMode sourceComponent: Rectangle{ anchors.fill: parent color: "transparent" //! red visualizer, in debug mode for the applets that use fillWidth or fillHeight //! green, for the rest border.color: (container.needsFillSpace && (container.sizeForFill>-1) && root.isHorizontal) ? "red" : "green" border.width: 1 } } Behavior on zoomScale { enabled: !root.globalDirectRender NumberAnimation { duration: 3*container.animationTime } } Behavior on zoomScale { enabled: root.globalDirectRender NumberAnimation { duration: root.directRenderAnimationTime } } function calculateScales( currentMousePosition ){ if (root.editMode || root.zoomFactor===1 || root.durationTime===0) { return; } var distanceFromHovered = Math.abs(index - layoutsContainer.hoveredIndex); // A new algorithm tryig to make the zoom calculation only once // and at the same time fixing glitches if ((distanceFromHovered == 0)&& (currentMousePosition > 0) ){ //use the new parabolicManager in order to handle all parabolic effect messages var scales = parabolicManager.applyParabolicEffect(index, currentMousePosition, center); /*if (root.latteApplet && Math.abs(index - root.latteAppletPos) > 2){ root.latteApplet.clearZoom(); }*/ //Left hiddenSpacer if(container.startEdge){ hiddenSpacerLeft.nScale = scales.leftScale - 1; } //Right hiddenSpacer ///there is one more item in the currentLayout ???? if(container.endEdge){ hiddenSpacerRight.nScale = scales.rightScale - 1; } zoomScale = root.zoomFactor; } } //scale function signalUpdateScale(nIndex, nScale, step){ if(container && (container.index === nIndex)){ //container.reconsiderAppletIconItem(); /*if (nScale !== 1){ if (applet && (applet.status === PlasmaCore.Types.HiddenStatus)){ console.log("WRONG SIGNAL for hidden applet with id:"+ index +" and zoom:"+nScale); } if (isSeparator){ console.log("WRONG SIGNAL for separator applet with id:"+ index +" and zoom:"+nScale); } if (container.isInternalViewSplitter){ console.log("WRONG SIGNAL for internal view splitter with id:"+ index +" and zoom:"+nScale); } }*/ if ( ((canBeHovered && !lockZoom ) || container.latteApplet) && (applet && applet.status !== PlasmaCore.Types.HiddenStatus) //&& (index != currentLayout.hoveredIndex) ){ if(!container.latteApplet){ if(nScale >= 0) zoomScale = nScale + step; else zoomScale = zoomScale + step; } } ///if the applet is hidden must forward its scale events to its neighbours /*else if ((applet && (applet.status === PlasmaCore.Types.HiddenStatus)) || container.isInternalViewSplitter){ if(layoutsContainer.hoveredIndex>index) root.updateScale(index-1, nScale, step); else if((layoutsContainer.hoveredIndex