Warning, /plasma/latte-dock/containment/package/contents/ui/abilities/AutoSize.qml is written in an unsupported language. File is not indexed.

0001 /*
0002     SPDX-FileCopyrightText: 2019 Michail Vourlakos <mvourlakos@gmail.com>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 import QtQuick 2.8
0007 
0008 import org.kde.plasma.plasmoid 2.0
0009 import org.kde.plasma.core 2.0 as PlasmaCore
0010 
0011 import org.kde.latte.core 0.2 as LatteCore
0012 
0013 Item {
0014     id: sizer
0015 
0016     // when there are only plasma style task managers OR any applets that fill width or height
0017     // the automatic icon size algorithm should better be disabled
0018     readonly property bool isActive: root.behaveAsDockWithMask
0019                                      && plasmoid.configuration.autoSizeEnabled
0020                                      && !root.containsOnlyPlasmaTasks
0021                                      && layouter.fillApplets<=0
0022                                      && !(root.inConfigureAppletsMode && plasmoid.configuration.alignment === LatteCore.Types.Justify) /*block shrinking for justify splitters*/
0023                                      && latteView
0024                                      && latteView.visibility.mode !== LatteCore.Types.SidebarOnDemand
0025                                      && latteView.visibility.mode !== LatteCore.Types.SidebarAutoHide
0026 
0027     property int iconSize: -1 //it is not set, this is the default
0028 
0029     readonly property bool inCalculatedIconSize: ((metrics.iconSize === sizer.iconSize) || (metrics.iconSize === metrics.maxIconSize))
0030     readonly property bool inAutoSizeAnimation: !inCalculatedIconSize
0031 
0032     readonly property int automaticStep: 8
0033     readonly property int historyMaxSize: 10
0034     readonly property int historyMinSize: 4
0035 
0036 
0037     //! Prediction History of the algorithm in order to track cases where the algorithm produces
0038     //! grows and shrinks endlessly
0039     property variant history: []
0040 
0041     //! required elements
0042     property Item layouts
0043     property Item layouter
0044     property Item metrics
0045     property Item visibility
0046 
0047     onInAutoSizeAnimationChanged: {
0048         if (inAutoSizeAnimation) {
0049             animations.needBothAxis.addEvent(sizer);
0050         } else {
0051             animations.needBothAxis.removeEvent(sizer);
0052         }
0053     }
0054 
0055     onIsActiveChanged: {
0056         clearHistory();
0057         updateIconSize();
0058     }
0059 
0060     Connections {
0061         target: root
0062         onContainsOnlyPlasmaTasksChanged: sizer.updateIconSize();
0063         onMaxLengthChanged: {
0064             if (latteView && latteView.positioner && !latteView.positioner.isOffScreen) {
0065                 sizer.updateIconSize();
0066             }
0067         }
0068     }
0069 
0070     Connections {
0071         target: metrics
0072 
0073         onPortionIconSizeChanged: {
0074             if (metrics.portionIconSize!==-1) {
0075                 sizer.updateIconSize();
0076             }
0077         }
0078     }
0079 
0080     Connections {
0081         target: latteView
0082         onWidthChanged:{
0083             if (root.isHorizontal && metrics.portionIconSize!==-1) {
0084                 sizer.updateIconSize();
0085             }
0086         }
0087 
0088         onHeightChanged:{
0089             if (root.isVertical && metrics.portionIconSize!==-1) {
0090                 sizer.updateIconSize();
0091             }
0092         }
0093     }
0094 
0095     Connections {
0096         target: latteView && latteView.positioner ? latteView.positioner : null
0097         onIsOffScreenChanged: {
0098             if (!latteView.positioner.isOffScreen) {
0099                 sizer.updateIconSize();
0100             }
0101         }
0102     }
0103 
0104     Connections {
0105         target: visibilityManager
0106         onInNormalStateChanged: {
0107             if (visibilityManager.inNormalState) {
0108                 sizer.updateIconSize();
0109             }
0110         }
0111     }
0112 
0113     //! Prediction History Functions
0114     function clearHistory() {
0115         history.length = 0;
0116     }
0117 
0118     function addPrediction(currentLength, prediction) {
0119         history.unshift({current: currentLength, predicted: prediction});
0120 
0121         /* console.log(" -- PREDICTION ARRAY -- ");
0122         for(var i=0; i<history.length; ++i) {
0123             console.log( i + ". " + history[i].current + " : " + history[i].predicted);
0124         }*/
0125 
0126         if (history.length > historyMaxSize) {
0127             history.splice(historyMinSize, history.length - historyMinSize);
0128         }
0129     }
0130 
0131     function producesEndlessLoop(currentLength, prediction) {
0132         if (history.length < 2) {
0133             return false;
0134         }
0135 
0136         if (history[1].current === currentLength
0137                 && history[1].predicted === prediction) {
0138             //! the current prediction is the same like two steps before in prediction history
0139 
0140             if(history[0].current > history[0].predicted && history[1].current < history[1].predicted) {
0141                 //! case2: the algorithm that is trying to SHRINK has already produced same results subsequently
0142                 console.log(" AUTOMATIC ITEM SIZE PROTECTOR, :: ENDLESS AUTOMATIC SIZE LOOP DETECTED");
0143                 return true;
0144             }
0145         }
0146 
0147         return false;
0148     }
0149 
0150 
0151     function updateIconSize() {
0152         if (!isActive && iconSize !== -1) {
0153             // restore original icon size
0154             iconSize = -1;
0155         }
0156 
0157         if ( !doubleCallAutomaticUpdateIconSize.running && !visibility.inRelocationHiding /*block too many calls and dont apply during relocatinon hiding*/
0158                 && (visibility.inNormalState && sizer.isActive) /*in normal and auto size active state*/
0159                 && (metrics.iconSize===metrics.maxIconSize || metrics.iconSize === sizer.iconSize) /*not during animations*/) {
0160 
0161             //!doubler timer
0162             if (!doubleCallAutomaticUpdateIconSize.secondTimeCallApplied) {
0163                 doubleCallAutomaticUpdateIconSize.start();
0164             } else {
0165                 doubleCallAutomaticUpdateIconSize.secondTimeCallApplied = false;
0166             }
0167 
0168             var layoutLength;
0169             var maxLength = root.maxLength;
0170 
0171             //console.log("------Entered check-----");
0172             //console.log("max length: "+ maxLength);
0173 
0174             layoutLength = (plasmoid.configuration.alignment === LatteCore.Types.Justify) ?
0175                         layouts.startLayout.length+layouts.mainLayout.length+layouts.endLayout.length : layouts.mainLayout.length
0176 
0177 
0178             var itemLength = metrics.totals.length;
0179 
0180             var toShrinkLimit = maxLength - (parabolic.factor.zoom * itemLength);
0181             //! to grow limit must be a little less than the shrink one in order to be more robust and
0182             //! not create endless loops from early calculations
0183             var toGrowLimit = maxLength - (1.2 * parabolic.factor.zoom * itemLength);
0184 
0185             //console.log("toShrinkLimit: "+ toShrinkLimit);
0186             //console.log("toGrowLimit: "+ toGrowLimit);
0187 
0188             var newIconSizeFound = false;
0189             if (layoutLength > toShrinkLimit) { //must shrink
0190                 // console.log("step3");
0191                 var nextIconSize = metrics.maxIconSize;
0192 
0193                 do {
0194                     nextIconSize = nextIconSize - automaticStep;
0195                     var factor = nextIconSize / metrics.iconSize;
0196                     var nextLength = factor * layoutLength;
0197 
0198                 } while ( (nextLength>toShrinkLimit) && (nextIconSize !== 16));
0199 
0200                 var intLength = Math.round(layoutLength);
0201                 var intNextLength = Math.round(nextLength);
0202 
0203                 iconSize = nextIconSize;
0204                 newIconSizeFound = true;
0205 
0206                 addPrediction(intLength, intNextLength);
0207                 // console.log("Step 3 - found:"+iconSize);
0208             } else if ((layoutLength<toGrowLimit
0209                         && (metrics.iconSize === iconSize)) ) { //must grow probably
0210                 // console.log("step4");
0211                 var nextIconSize2 = iconSize;
0212                 var foundGoodSize = -1;
0213 
0214                 do {
0215                     nextIconSize2 = nextIconSize2 + automaticStep;
0216                     var factor2 = nextIconSize2 / iconSize;
0217                     var nextLength2 = factor2 * layoutLength;
0218 
0219                     if (nextLength2 < toGrowLimit) {
0220                         foundGoodSize = nextIconSize2;
0221                     }
0222                 } while ( (nextLength2<toGrowLimit) && (nextIconSize2 !== metrics.maxIconSize ));
0223 
0224                 var intLength2 = Math.round(layoutLength);
0225                 var intNextLength2 = Math.round(nextLength2);
0226 
0227                 if (foundGoodSize > 0 && !producesEndlessLoop(intLength2, intNextLength2)) {
0228                     if (foundGoodSize === metrics.maxIconSize) {
0229                         iconSize = -1;
0230                     } else {
0231                         iconSize = foundGoodSize;
0232                     }
0233                     newIconSizeFound = true
0234 
0235                     addPrediction(intLength2, intNextLength2);
0236                     //        console.log("Step 4 - found:"+iconSize);
0237                 } else {
0238                     //       console.log("Step 4 - did not found...");
0239                 }
0240             }
0241         }
0242     }
0243 
0244     //! This functions makes sure to call the updateIconSize(); function which is costly
0245     //! one more time after its last call to confirm the applied icon size found
0246     Timer{
0247         id:doubleCallAutomaticUpdateIconSize
0248         interval: 1000
0249         property bool secondTimeCallApplied: false
0250 
0251         onTriggered: {
0252             if (!secondTimeCallApplied) {
0253                 secondTimeCallApplied = true;
0254                 sizer.updateIconSize();
0255             }
0256         }
0257     }
0258 }