/* * Copyright 2019 Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.8 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.plasmoid 2.0 import org.kde.latte 0.2 as Latte Item { id: sizer // when there are only plasma style task managers OR any applets that fill width or height // the automatic icon size algorithm should better be disabled readonly property bool isActive: !root.containsOnlyPlasmaTasks && layoutsContainer.fillApplets<=0 property bool automaticSizeAnimation: false readonly property int automaticStep: 8 readonly property int historyMaxSize: 10 readonly property int historyMinSize: 4 property int automaticIconSizeBasedSize: -1 //it is not set, this is the default //! Prediction History of the algorithm in order to track cases where the algorithm produces //! grows and shrinks endlessly property variant history: [] onAutomaticIconSizeBasedSizeChanged: { if (!automaticSizeAnimation) { automaticSizeAnimation = true; root.slotAnimationsNeedBothAxis(1); } } onIsActiveChanged: clearHistory(); Connections { target: root onContainsOnlyPlasmaTasksChanged: sizer.updateAutomaticIconSize(); onEditModeChanged: sizer.updateAutomaticIconSize(); onMaxLengthChanged: { if (root.editMode) { sizer.updateAutomaticIconSize(); } } onProportionIconSizeChanged: { if (root.proportionIconSize!==-1) { sizer.updateAutomaticIconSize(); } } onIconSizeChanged: { if (((root.iconSize === sizer.automaticIconSizeBasedSize) || (root.iconSize === root.maxIconSize)) && sizer.automaticSizeAnimation){ root.slotAnimationsNeedBothAxis(-1); sizer.automaticSizeAnimation=false; } } } Connections { target: latteView onWidthChanged:{ if (root.isHorizontal && root.proportionIconSize!==-1) { sizer.updateAutomaticIconSize(); } } onHeightChanged:{ if (root.isVertical && root.proportionIconSize!==-1) { sizer.updateAutomaticIconSize(); } } } //! Prediction History Functions function clearHistory() { history.length = 0; } function addPrediction(currentLength, prediction) { history.unshift({current: currentLength, predicted: prediction}); /* console.log(" -- PREDICTION ARRAY -- "); for(var i=0; i historyMaxSize) { history.splice(historyMinSize, history.length - historyMinSize); } } function producesEndlessLoop(currentLength, prediction) { if (history.length < 2) { return false; } if (history[1].current === currentLength && history[1].predicted === prediction) { //! the current prediction is the same like two steps before in prediction history if(history[0].current > history[0].predicted && history[1].current < history[1].predicted) { //! case2: the algorithm that is trying to SHRINK has already produced same results subsequently console.log(" AUTOMATIC ITEM SIZE PROTECTOR, :: ENDLESS AUTOMATIC SIZE LOOP DETECTED"); return true; } } return false; } function updateAutomaticIconSize() { if ( !doubleCallAutomaticUpdateIconSize.running && !visibilityManager.inTempHiding && ((visibilityManager.normalState || root.editMode) && (sizer.isActive || (!sizer.isActive && root.iconSize!==root.maxIconSize))) && (root.iconSize===root.maxIconSize || root.iconSize === sizer.automaticIconSizeBasedSize) ) { //!doubler timer if (!doubleCallAutomaticUpdateIconSize.secondTimeCallApplied) { doubleCallAutomaticUpdateIconSize.start(); } else { doubleCallAutomaticUpdateIconSize.secondTimeCallApplied = false; } var layoutLength; var maxLength = root.maxLength; //console.log("------Entered check-----"); //console.log("max length: "+ maxLength); if (root.isVertical) { layoutLength = (plasmoid.configuration.panelPosition === Latte.Types.Justify) ? layoutsContainer.startLayout.height+layoutsContainer.mainLayout.height+layoutsContainer.endLayout.height : layoutsContainer.mainLayout.height } else { layoutLength = (plasmoid.configuration.panelPosition === Latte.Types.Justify) ? layoutsContainer.startLayout.width+layoutsContainer.mainLayout.width+layoutsContainer.endLayout.width : layoutsContainer.mainLayout.width } var itemLength = root.iconSize + lengthMargins; var toShrinkLimit = maxLength - (root.zoomFactor * itemLength); //! to grow limit must be a little less than the shrink one in order to be more robust and //! not create endless loops from early calculations var toGrowLimit = maxLength - (1.2 * root.zoomFactor * itemLength); //console.log("toShrinkLimit: "+ toShrinkLimit); //console.log("toGrowLimit: "+ toGrowLimit); var newIconSizeFound = false; if (layoutLength > toShrinkLimit) { //must shrink // console.log("step3"); var nextIconSize = root.maxIconSize; do { nextIconSize = nextIconSize - automaticStep; var factor = nextIconSize / root.iconSize; var nextLength = factor * layoutLength; } while ( (nextLength>toShrinkLimit) && (nextIconSize !== 16)); var intLength = Math.round(layoutLength); var intNextLength = Math.round(nextLength); automaticIconSizeBasedSize = nextIconSize; newIconSizeFound = true; addPrediction(intLength, intNextLength); // console.log("Step 3 - found:"+automaticIconSizeBasedSize); } else if ((layoutLength 0 && !producesEndlessLoop(intLength2, intNextLength2)) { if (foundGoodSize === root.maxIconSize) { automaticIconSizeBasedSize = -1; } else { automaticIconSizeBasedSize = foundGoodSize; } newIconSizeFound = true addPrediction(intLength2, intNextLength2); // console.log("Step 4 - found:"+automaticIconSizeBasedSize); } else { // console.log("Step 4 - did not found..."); } } } } //! This functions makes sure to call the updateAutomaticIconSize(); function which is costly //! one more time after its last call to confirm the applied icon size found Timer{ id:doubleCallAutomaticUpdateIconSize interval: 1000 property bool secondTimeCallApplied: false onTriggered: { if (!secondTimeCallApplied) { secondTimeCallApplied = true; sizer.updateAutomaticIconSize(); } } } }