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

0001 /*
0002     SPDX-FileCopyrightText: 2020 Michail Vourlakos <mvourlakos@gmail.com>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 import QtQuick 2.7
0007 import org.kde.plasma.plasmoid 2.0
0008 
0009 import org.kde.latte.core 0.2 as LatteCore
0010 
0011 import "./layouter" as LayouterElements
0012 
0013 Item {
0014     property Item layouts: null
0015     property Item animations: null
0016     property Item indexer: null
0017 
0018     readonly property int fillApplets: startLayout.fillApplets + mainLayout.fillApplets + endLayout.fillApplets
0019     readonly property int shownApplets: startLayout.shownApplets + mainLayout.shownApplets + endLayout.shownApplets
0020     readonly property int sizeWithNoFillApplets: startLayout.sizeWithNoFillApplets + mainLayout.sizeWithNoFillApplets + endLayout.sizeWithNoFillApplets
0021 
0022     readonly property int maxLength: root.myView.alignment === LatteCore.Types.Justify ? contentsMaxLength : Math.min(root.minLength, contentsMaxLength)
0023 
0024     readonly property int contentsMaxLength: root.maxLength - background.totals.paddingsLength
0025 
0026     readonly property Item startLayout: LayouterElements.AppletsContainer {
0027         grid: layouts.startLayout
0028     }
0029 
0030     readonly property Item mainLayout: LayouterElements.AppletsContainer {
0031         grid: layouts.mainLayout
0032     }
0033 
0034     readonly property Item endLayout: LayouterElements.AppletsContainer {
0035         grid: layouts.endLayout
0036     }
0037 
0038     onFillAppletsChanged: layouter.updateSizeForAppletsInFill();
0039     onShownAppletsChanged: layouter.updateSizeForAppletsInFill();
0040     onSizeWithNoFillAppletsChanged: layouter.updateSizeForAppletsInFill();
0041 
0042     //!         FILLWIDTH/FILLHEIGHT COMPUTATIONS
0043     //! Computations in order to calculate correctly the sizes for applets
0044     //! that are requesting fillWidth or fillHeight
0045 
0046     //! qBound style function that is specialized in Layouts
0047     //! meaning that -1 values are ignored for fillWidth(s)/Height(s)
0048     function appletPreferredLength(min, pref, max){
0049         if (max === -1) {
0050             max = pref === -1 ? min : pref;
0051         }
0052 
0053         if (pref === -1) {
0054             pref = max === -1 ? min : pref;
0055         }
0056 
0057         return  Math.min(Math.max(min,pref),max);
0058     }
0059 
0060 
0061     //! initialize AppletItems flag "inFillCalculations" in order
0062     //! to inform them that new calculations are taking place
0063     function initLayoutForFillsCalculations(layout) {
0064         for(var i=0; i<layout.children.length; ++i) {
0065             var curApplet = layout.children[i];
0066             if (curApplet.isAutoFillApplet) {
0067                 curApplet.inFillCalculations = true;
0068             }
0069         }
0070     }
0071 
0072     //! during step1/pass1 all applets that provide valid metrics (minimum/preferred/maximum values)
0073     //! they gain a valid space in order to draw themeselves
0074     function computeStep1ForLayout(layout, availableSpace, sizePerApplet, noOfApplets, inMaxAutoFillCalculations) {
0075         for(var i=0; i<layout.children.length; ++i) {
0076             var curApplet = layout.children[i];
0077 
0078             // console.log( "org.kde.latte s3_-1 " + curApplet.pluginName + " : "+ curApplet.index +" (" +curApplet.isAutoFillApplet+","+!curApplet.isHidden +") ");
0079             // console.log( "org.kde.latte s3_-1 " + curApplet.pluginName + " : "+ availableSpace + " _ " + sizePerApplet + " _ " + noOfApplets);
0080 
0081             if (curApplet && curApplet.isAutoFillApplet && !curApplet.isHidden
0082                     && (curApplet.applet || curApplet.isInternalViewSplitter)) {
0083                 var minSize = curApplet.appletMinimumLength;
0084                 var prefSize = curApplet.appletPreferredLength;
0085                 var maxSize = curApplet.appletMaximumLength;
0086 
0087                 // console.log( "org.kde.latte s3_0 " + curApplet.pluginName + " : "+ curApplet.index +" (" +minSize+","+prefSize+","+maxSize+") ");
0088 
0089                 minSize = minSize>=0 && minSize!==Infinity ? minSize : -1;
0090                 prefSize = minSize>=0 && prefSize!==Infinity ? prefSize : -1;
0091 
0092                 //! Qt ignores maximumlength=0 for applets that have set Layout.fillLength flag
0093                 //! this was tracked through bug #445869, mediacontroller_plus applet case
0094                 maxSize = maxSize>0 && maxSize!== Infinity ? maxSize : -1;
0095 
0096                 var appliedSize = -1;
0097                 //! check if the applet does not provide any valid metrics and for that case
0098                 //! the system must decide what space to be given after the applets that provide
0099                 //! nice metrics are assigned their sizes
0100                 //var systemDecide = ((minSize<0) && (prefSize<0) && (maxSize<0));
0101 
0102                 var staticsize = (minSize>=0 && (maxSize === minSize) && (maxSize !== Infinity));
0103                 var systemDecide = (prefSize<0 && !staticsize);
0104 
0105                 if (!systemDecide) {
0106                     if (noOfApplets>1) {
0107                         appliedSize = appletPreferredLength(minSize, prefSize, maxSize);
0108 
0109                         // console.log( "org.kde.latte s3_1 " + curApplet.pluginName + " : (" +minSize+","+prefSize+","+maxSize+") -> " + appliedSize);
0110                     } else if (noOfApplets===1) {
0111                         //! at this step if only one applet has remained for which the max size is not null,
0112                         //! then for this applet we make sure the maximum size does not exceed the available space
0113                         //! in order for the applet to not be drawn outside the boundaries
0114                         appliedSize = appletPreferredLength(minSize, prefSize, Math.min(maxSize, sizePerApplet));
0115 
0116                         // console.log( "org.kde.latte s3_2 " + curApplet.pluginName + " : (" +minSize+","+prefSize+","+maxSize+") -> " + appliedSize);
0117                     }
0118 
0119                     //! appliedSize is valid and is also lower than the availableSpace, if it is not lower then
0120                     //! for this applet the needed space will be provided as a second pass in a fair way
0121                     //! between all remained applets that did not gain a valid fill space
0122                     if (appliedSize>=0 && appliedSize<=sizePerApplet) {
0123                         var properSize = Math.min(appliedSize, availableSpace);                       
0124                         var adjustedSize = curApplet.isHidden ? 0 : properSize;
0125 
0126                         if (inMaxAutoFillCalculations) {
0127                             curApplet.maxAutoFillLength = adjustedSize;
0128                         } else {
0129                             curApplet.minAutoFillLength = adjustedSize;
0130                         }
0131 
0132                         curApplet.inFillCalculations = false;
0133                         availableSpace = Math.max(0, availableSpace - curApplet.maxAutoFillLength);
0134                         noOfApplets = noOfApplets - 1;
0135                         sizePerApplet = noOfApplets > 1 ? Math.floor(availableSpace / noOfApplets) : availableSpace;
0136 
0137                         // console.log( "org.kde.latte s3_3 " + curApplet.pluginName + " assigned: " + curApplet.maxAutoFillLength);
0138                     }
0139                 }
0140 
0141                 // console.log("org.kde.latte s3_r " +curApplet.pluginName + " : " + availableSpace + " _ " + sizePerApplet + " _ " + noOfApplets + "\n");
0142             }
0143         }
0144 
0145         return [availableSpace, sizePerApplet, noOfApplets];
0146     }
0147 
0148     //! during step2/pass2 all the applets with fills
0149     //! that remained with no computations from pass1
0150     //! are updated with the algorithm's proposed size
0151     function computeStep2ForLayout(layout, sizePerApplet, noOfApplets, inMaxAutoFillCalculations) {
0152         if (sizePerApplet>=0) {
0153             if (noOfApplets === 0) {
0154                 //! when all applets have assigned some size and there is still free space, we must find
0155                 //! the most demanding space applet and assign the remaining space to it
0156 
0157                 var mostDemandingAppletSize = 0;
0158                 var mostDemandingApplet = undefined;
0159 
0160                 //! applets with no strong opinion
0161                 var neutralAppletsNo = 0;
0162                 var neutralApplets = [];
0163 
0164                 for(var i=0; i<layout.children.length; ++i) {
0165                     var curApplet = layout.children[i];
0166 
0167                     //! the most demanding applet is the one that has maximum size set to Infinity
0168                     //! AND is not Neutral, meaning that it provided some valid metrics
0169                     //! AND at the same time gained from step one the biggest space
0170                     if (curApplet && curApplet.isAutoFillApplet && !curApplet.isHidden
0171                             && (curApplet.applet || curApplet.isInternalViewSplitter)) {
0172                         var minSize = curApplet.appletMinimumLength;
0173                         var prefSize = curApplet.appletPreferredLength;
0174                         var maxSize = curApplet.appletMaximumLength;
0175 
0176                         var isNeutral = (minSize<=0 && prefSize<=0);
0177 
0178                         // console.log( " org.kde.latte s4_0 " + curApplet.pluginName + " : (" +minSize+","+prefSize+","+maxSize+") ");
0179 
0180                         if (!isNeutral
0181                                 && ((inMaxAutoFillCalculations && curApplet.maxAutoFillLength>mostDemandingAppletSize)
0182                                     || (!inMaxAutoFillCalculations && curApplet.minAutoFillLength>mostDemandingAppletSize) )) {
0183                             mostDemandingApplet = curApplet;
0184                             mostDemandingAppletSize = inMaxAutoFillCalculations ? curApplet.maxAutoFillLength : curApplet.minAutoFillLength;
0185                         } else if (isNeutral) {
0186                             neutralAppletsNo = neutralAppletsNo + 1;
0187                             neutralApplets.push(curApplet);
0188                         }
0189                     }
0190                 }
0191 
0192                 if (mostDemandingApplet) {
0193                     //! the most demanding applet gains all the remaining space
0194 
0195                     if (inMaxAutoFillCalculations) {
0196                         mostDemandingApplet.maxAutoFillLength = mostDemandingApplet.maxAutoFillLength + sizePerApplet;
0197                     } else {
0198                         mostDemandingApplet.minAutoFillLength = mostDemandingApplet.minAutoFillLength + sizePerApplet;
0199                     }
0200 
0201                     /*if (inMaxAutoFillCalculations) {
0202                         console.log(" org.kde.latte s4_1  "+ mostDemandingApplet.applet.pluginName + " assigned max : "  + mostDemandingApplet.maxAutoFillLength + "\n");
0203                     } else {
0204                         console.log(" org.kde.latte s4_1  "+ mostDemandingApplet.applet.pluginName + " assigned min: "  + mostDemandingApplet.minAutoFillLength + "\n");
0205                     }*/
0206                 } else if (neutralAppletsNo>0) {
0207                     //! if no demanding applets was found then the available space is splitted equally
0208                     //! between all neutralApplets
0209                     var adjustedAppletSize = (sizePerApplet / neutralAppletsNo);
0210                     for (var j=0; j<neutralApplets.length; ++j) {
0211                         // console.log(" org.kde.latte s4_2.0  "+ neutralApplets[j].pluginName + " _ " + neutralApplets[j].maxAutoFillLength + " _ " + adjustedAppletSize);
0212 
0213                         if (inMaxAutoFillCalculations) {
0214                             neutralApplets[j].maxAutoFillLength = neutralApplets[j].maxAutoFillLength + adjustedAppletSize;
0215                         } else {
0216                             neutralApplets[j].minAutoFillLength = neutralApplets[j].minAutoFillLength + adjustedAppletSize;
0217                         }
0218 
0219                         // console.log(" org.kde.latte s4_2.1  "+ neutralApplets[j].pluginName + " assigned: "  + sizePerApplet + "\n");
0220                     }
0221                 }
0222             } else {
0223                 for(var i=0; i<layout.children.length; ++i) {
0224                     var curApplet = layout.children[i];
0225 
0226                     if (curApplet && curApplet.isAutoFillApplet && !curApplet.isHidden && curApplet.inFillCalculations) {
0227                         if (inMaxAutoFillCalculations) {
0228                             curApplet.maxAutoFillLength = Math.max(curApplet.appletMinimumLength,sizePerApplet);
0229                         } else {
0230                             curApplet.minAutoFillLength = Math.max(curApplet.appletMinimumLength,sizePerApplet);
0231                         }
0232 
0233                         // console.log(" org.kde.latte s4_3  "+ curApplet.pluginName + " assigned: "  + sizePerApplet + "\n");
0234                         curApplet.inFillCalculations = false;
0235                     }
0236                 }
0237             }
0238         }
0239     }
0240 
0241     //! initialize the three layouts and execute the step1/phase1
0242     //! it is used when the Centered (Main)Layout is used only or when the Main(Layout)
0243     //! is empty in Justify mode
0244     function initializationPhase(availableSpace, sizePerApplet, noOfApplets, inMaxAutoFillCalculations){
0245         if (root.myView.alignment === LatteCore.Types.Justify) {
0246             initLayoutForFillsCalculations(startLayout.grid);
0247             initLayoutForFillsCalculations(endLayout.grid);
0248         }
0249         initLayoutForFillsCalculations(mainLayout.grid);
0250 
0251         // console.log("s3...");
0252 
0253         //! first pass in order to update sizes for applet that want to fill space
0254         //! but their maximum metrics are lower than the sizePerApplet
0255         var res = computeStep1ForLayout(mainLayout.grid, availableSpace, sizePerApplet, noOfApplets, inMaxAutoFillCalculations);
0256         availableSpace = res[0]; sizePerApplet = res[1]; noOfApplets = res[2];
0257 
0258         // console.log( " i1 : " + availableSpace + " _ " + sizePerApplet + " _ " + noOfApplets );
0259 
0260         if (root.myView.alignment === LatteCore.Types.Justify) {
0261             res = computeStep1ForLayout(startLayout.grid, availableSpace, sizePerApplet, noOfApplets, inMaxAutoFillCalculations);
0262             availableSpace = res[0]; sizePerApplet = res[1]; noOfApplets = res[2];
0263             // console.log( " i2 : " + availableSpace + " _ " + sizePerApplet + " _ " + noOfApplets );
0264 
0265             res = computeStep1ForLayout(endLayout.grid, availableSpace, sizePerApplet, noOfApplets, inMaxAutoFillCalculations);
0266             availableSpace = res[0]; sizePerApplet = res[1]; noOfApplets = res[2];
0267             // console.log( " i3 : " + availableSpace + " _ " + sizePerApplet + " _ " + noOfApplets );
0268         }
0269 
0270         return [availableSpace, sizePerApplet, noOfApplets];
0271     }
0272 
0273     function updateFillAppletsWithTwoSteps(inMaxAutoFillCalculations) {
0274         var noA = startLayout.fillApplets + mainLayout.fillApplets + endLayout.fillApplets;
0275         var max_length = inMaxAutoFillCalculations ? contentsMaxLength : root.minLength
0276 
0277         // console.log(" S3 _ SIZES ::: " + max_length + " ___ " + inMaxAutoFillCalculations + " __ " + startLayout.sizeWithNoFillApplets + " ___ " + mainLayout.sizeWithNoFillApplets + " ___ " + endLayout.sizeWithNoFillApplets);
0278 
0279         //! compute the two free spaces around the centered layout
0280         //! they are called start and end accordingly
0281         var halfMainLayout = mainLayout.sizeWithNoFillApplets / 2;
0282         var availableSpaceStart = Math.max(0, max_length/2 - startLayout.sizeWithNoFillApplets - halfMainLayout /*- layoutsContainer.backgroundTailLength*/);
0283         var availableSpaceEnd = Math.max(0, max_length/2 - endLayout.sizeWithNoFillApplets - halfMainLayout /*- layoutsContainer.backgroundHeadLength*/);
0284         var availableSpace;
0285 
0286         if (mainLayout.fillApplets === 0 || (startLayout.shownApplets ===0 && endLayout.shownApplets===0)){
0287             //! no fill applets in main OR we are in alignment that all applets are in main
0288             availableSpace = availableSpaceStart + availableSpaceEnd - mainLayout.sizeWithNoFillApplets;
0289         } else {
0290             //! use the minimum available space in order to avoid overlaps
0291             availableSpace = 2 * Math.min(availableSpaceStart, availableSpaceEnd) - mainLayout.sizeWithNoFillApplets;
0292         }
0293 
0294         var sizePerAppletMain = mainLayout.fillApplets > 0 ? availableSpace / noA : 0 ;
0295 
0296         var noStart = startLayout.fillApplets;
0297         var noMain = mainLayout.fillApplets;
0298         var noEnd = endLayout.fillApplets;
0299 
0300         //! initialize the computations
0301         initLayoutForFillsCalculations(startLayout.grid, inMaxAutoFillCalculations);
0302         initLayoutForFillsCalculations(mainLayout.grid, inMaxAutoFillCalculations);
0303         initLayoutForFillsCalculations(endLayout.grid, inMaxAutoFillCalculations);
0304 
0305         var res;
0306 
0307         // console.log(" org.kde.latte S3.1 main fill applets :: " + mainLayout.fillApplets);
0308         //! first pass
0309         if (mainLayout.fillApplets > 0){
0310             res = computeStep1ForLayout(mainLayout.grid, availableSpace, sizePerAppletMain, noMain, inMaxAutoFillCalculations);
0311             sizePerAppletMain = res[1]; noMain = res[2];
0312             var dif = (availableSpace - res[0]) / 2;
0313             availableSpaceStart = availableSpaceStart - dif;
0314             availableSpaceEnd = availableSpaceEnd - dif;
0315         }
0316 
0317         var sizePerAppletStart = startLayout.fillApplets > 0 ? availableSpaceStart / noStart : 0 ;
0318         var sizePerAppletEnd = endLayout.fillApplets > 0 ? availableSpaceEnd / noEnd : 0 ;
0319 
0320         if (startLayout.fillApplets > 0) {
0321             res = computeStep1ForLayout(startLayout.grid, availableSpaceStart, sizePerAppletStart, noStart, inMaxAutoFillCalculations);
0322             availableSpaceStart = res[0]; sizePerAppletStart = res[1]; noStart = res[2];
0323         }
0324         if (endLayout.fillApplets > 0) {
0325             res = computeStep1ForLayout(endLayout.grid, availableSpaceEnd, sizePerAppletEnd, noEnd, inMaxAutoFillCalculations);
0326             availableSpaceEnd = res[0]; sizePerAppletEnd = res[1]; noEnd = res[2];
0327         }
0328 
0329         ////
0330         //! second pass
0331 
0332         // console.log(" S ::: " +startLayout.fillApplets + " _ " + sizePerAppletStart + " _ " + noStart);
0333 
0334         if (startLayout.fillApplets > 0) {
0335             if (mainLayout.fillApplets > 0) {
0336                 //! finally adjust ALL startLayout fill applets size in mainlayouts final length
0337                 noStart = startLayout.fillApplets;
0338                 sizePerAppletStart = ((max_length/2) - (mainLayout.grid.length/2) - startLayout.sizeWithNoFillApplets) / noStart;
0339             }
0340 
0341             computeStep2ForLayout(startLayout.grid, sizePerAppletStart, noStart, inMaxAutoFillCalculations);
0342         }
0343 
0344         if (endLayout.fillApplets > 0) {
0345             if (mainLayout.fillApplets > 0) {
0346                 //! finally adjust ALL endLayout fill applets size in mainlayouts final length
0347                 noEnd = endLayout.fillApplets;
0348                 sizePerAppletEnd = ((max_length/2) - (mainLayout.grid.length/2) - endLayout.sizeWithNoFillApplets) / noEnd;
0349             }
0350 
0351             computeStep2ForLayout(endLayout.grid, sizePerAppletEnd, noEnd, inMaxAutoFillCalculations);
0352         }
0353 
0354         if (mainLayout.fillApplets > 0) {
0355             var halfRemained = (max_length/2) - (mainLayout.grid.length/2);
0356             var freeSpaceAfterStart = halfRemained - startLayout.grid.length;
0357             var freeSpaceBeforeEnd = halfRemained - endLayout.grid.length;
0358 
0359             if (freeSpaceAfterStart > 0 && freeSpaceBeforeEnd>0) {
0360                 if (mainLayout.fillApplets > 0) {
0361                     var minimumHalfAppletSizePossible = Math.min(freeSpaceAfterStart, freeSpaceBeforeEnd);
0362                     sizePerAppletMain = Math.max(0, (minimumHalfAppletSizePossible * 2)/mainLayout.fillApplets);
0363                 }
0364 
0365                 computeStep2ForLayout(mainLayout.grid, sizePerAppletMain, noMain, inMaxAutoFillCalculations); //default behavior
0366             }
0367         }
0368     }
0369 
0370     function updateFillAppletsWithOneStep(inMaxAutoFillCalculations) {
0371         var max_length = inMaxAutoFillCalculations ? contentsMaxLength : root.minLength
0372         var noA = startLayout.fillApplets + mainLayout.fillApplets + endLayout.fillApplets;
0373 
0374         // console.log(" org.kde.latte S2 _ SIZES ::: " + max_length + " ___ " + inMaxAutoFillCalculations + " __ " + startLayout.sizeWithNoFillApplets + " ___ " + mainLayout.sizeWithNoFillApplets + " ___ " + endLayout.sizeWithNoFillApplets);
0375 
0376         var availableSpace = Math.max(0, max_length - startLayout.sizeWithNoFillApplets - mainLayout.sizeWithNoFillApplets - endLayout.sizeWithNoFillApplets);
0377         var sizePerApplet = availableSpace / noA;
0378 
0379         var res = initializationPhase(availableSpace, sizePerApplet, noA, inMaxAutoFillCalculations);
0380         availableSpace = res[0];  sizePerApplet = res[1]; noA = res[2];
0381 
0382         // console.log("s4...");
0383 
0384         //! after step1 there is a chance that all applets were assigned a valid space
0385         //! but at the same time some space remained free. In such case we make sure
0386         //! that remained space will be assigned to the most demanding applet.
0387         //! This is achieved by <layout>No values. For step2 passing value!=0
0388         //! means default step2 behavior BUT value=0 means that remained space
0389         //! must be also assigned at the end.
0390         var remainedSpace = (noA === 0 && sizePerApplet > 0) ? true : false
0391 
0392         var startNo = -1;
0393         var mainNo = -1;
0394         var endNo = -1;
0395 
0396         if (remainedSpace) {
0397             if (startLayout.fillApplets > 0) {
0398                 startNo = 0;
0399             } else if (endLayout.fillApplets > 0) {
0400                 endNo = 0;
0401             } else if (mainLayout.fillApplets > 0) {
0402                 mainNo = 0;
0403             }
0404         }
0405 
0406         //! second pass in order to update sizes for applet that want to fill space
0407         //! these applets get the direct division of the available free space that
0408         //! remained from step1 OR the the free available space that no applet requested yet
0409 
0410         computeStep2ForLayout(startLayout.grid, sizePerApplet, startNo, inMaxAutoFillCalculations); //default behavior
0411         computeStep2ForLayout(mainLayout.grid, sizePerApplet, mainNo, inMaxAutoFillCalculations); //default behavior
0412         computeStep2ForLayout(endLayout.grid, sizePerApplet, endNo, inMaxAutoFillCalculations); //default behavior
0413 
0414         // console.log(" org.kde.latte s5...");
0415     }
0416 
0417 
0418     function _updateSizeForAppletsInFill() {
0419         if (inNormalFillCalculationsState) {
0420             // console.log(" org.kde.latte -------------");
0421             // console.log(" org.kde.latte s1...");
0422             var noA = startLayout.fillApplets + mainLayout.fillApplets + endLayout.fillApplets;
0423 
0424             if (noA === 0) {
0425                 return;
0426             }
0427 
0428             var use_maximum_length = true;
0429 
0430             if (mainLayout.shownApplets === 0 || root.myView.alignment !== LatteCore.Types.Justify) {
0431                 updateFillAppletsWithOneStep(use_maximum_length);
0432                 updateFillAppletsWithOneStep(!use_maximum_length);
0433             } else {
0434                 //! Justify mode in all remaining cases
0435                 updateFillAppletsWithTwoSteps(use_maximum_length);
0436                 updateFillAppletsWithTwoSteps(!use_maximum_length);
0437             }
0438         }
0439     }
0440 }