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 }