introduce Layouter ability
parent
2a91cb55c1
commit
2ef0cdd944
@ -1,336 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2018 Michail Vourlakos <mvourlakos@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//! FILLWIDTH/FILLHEIGHT COMPUTATIONS
|
||||
//! Computations in order to calculate correctly the sizes for applets
|
||||
//! that are requesting fillWidth or fillHeight
|
||||
|
||||
//! qBound style function that is specialized in Layouts
|
||||
//! meaning that -1 values are ignored for fillWidth(s)/Height(s)
|
||||
function layoutBound(min, pref, max){
|
||||
if (max === -1) {
|
||||
max = pref === -1 ? min : pref;
|
||||
}
|
||||
|
||||
if (pref === -1) {
|
||||
pref = max === -1 ? min : pref;
|
||||
}
|
||||
|
||||
return Math.min(Math.max(min,pref),max);
|
||||
}
|
||||
|
||||
|
||||
//! initialize AppletItems flag "inFillCalculations" in order
|
||||
//! to inform them that new calculations are taking place
|
||||
function initLayoutForFillsCalculations(layout) {
|
||||
for(var i=0; i<layout.children.length; ++i) {
|
||||
var curApplet = layout.children[i];
|
||||
if (curApplet.needsFillSpace) {
|
||||
curApplet.inFillCalculations = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! during step1/pass1 all applets that provide valid metrics (minimum/preferred/maximum values)
|
||||
//! they gain a valid space in order to draw themeselves
|
||||
function computeStep1ForLayout(layout, availableSpace, sizePerApplet, noOfApplets) {
|
||||
for(var i=0; i<layout.children.length; ++i) {
|
||||
var curApplet = layout.children[i];
|
||||
|
||||
if (curApplet.needsFillSpace) {
|
||||
if (curApplet && curApplet.applet && curApplet.applet.Layout) {
|
||||
var minSize = root.isVertical ? curApplet.applet.Layout.minimumHeight : curApplet.applet.Layout.minimumWidth;
|
||||
var prefSize = root.isVertical ? curApplet.applet.Layout.preferredHeight : curApplet.applet.Layout.preferredWidth;
|
||||
var maxSize = root.isVertical ? curApplet.applet.Layout.maximumHeight : curApplet.applet.Layout.maximumWidth;
|
||||
|
||||
// console.log( " s3_0 " + curApplet.applet.pluginName + " : (" +minSize+","+prefSize+","+maxSize+") ");
|
||||
|
||||
minSize = minSize>=0 && minSize!==Infinity ? minSize : -1;
|
||||
prefSize = minSize>=0 && prefSize!==Infinity ? prefSize : -1;
|
||||
maxSize = maxSize>=0 && maxSize!== Infinity ? maxSize : -1;
|
||||
|
||||
var appliedSize = -1;
|
||||
|
||||
//! check if the applet does not provide any valid metrics and for that case
|
||||
//! the system must decide what space to be given after the applets that provide
|
||||
//! nice metrics are assigned their sizes
|
||||
var systemDecide = ((minSize<0) && (prefSize<0) && (maxSize<0));
|
||||
|
||||
if (!systemDecide) {
|
||||
if (noOfApplets>1) {
|
||||
appliedSize = layoutBound(minSize, prefSize, maxSize);
|
||||
|
||||
// console.log( " s3_1 " + curApplet.applet.pluginName + " : (" +minSize+","+prefSize+","+maxSize+") -> " + appliedSize);
|
||||
} else if (noOfApplets===1) {
|
||||
//! at this step if only one applet has remained for which the max size is not null,
|
||||
//! then for this applet we make sure the maximum size does not exceed the available space
|
||||
//! in order for the applet to not be drawn outside the boundaries
|
||||
appliedSize = layoutBound(minSize, prefSize, Math.min(maxSize, sizePerApplet));
|
||||
|
||||
// console.log( " s3_2 " + curApplet.applet.pluginName + " : (" +minSize+","+prefSize+","+maxSize+") -> " + appliedSize);
|
||||
}
|
||||
|
||||
//! appliedSize is valid and is also lower than the availableSpace, if it is not lower then
|
||||
//! for this applet the needed space will be provided as a second pass in a fair way
|
||||
//! between all remained applets that did not gain a valid fill space
|
||||
if (appliedSize>=0 && appliedSize<=sizePerApplet) {
|
||||
var properSize = Math.min(appliedSize, availableSpace);
|
||||
var thickness = root.isVertical ? root.width : root.height;
|
||||
var adjustedSize = curApplet.isHidden ? 0 : Math.max(thickness, properSize);
|
||||
|
||||
curApplet.sizeForFill = adjustedSize;
|
||||
curApplet.inFillCalculations = false;
|
||||
availableSpace = Math.max(0, availableSpace - curApplet.sizeForFill);
|
||||
noOfApplets = noOfApplets - 1;
|
||||
sizePerApplet = noOfApplets > 1 ? Math.floor(availableSpace / noOfApplets) : availableSpace;
|
||||
|
||||
// console.log( " s3_3 " + curApplet.applet.pluginName + " assigned: " + curApplet.sizeForFill);
|
||||
}
|
||||
}
|
||||
|
||||
// console.log("s3_r " +curApplet.applet.pluginName + " : " + availableSpace + " _ " + sizePerApplet + " _ " + noOfApplets + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [availableSpace, sizePerApplet, noOfApplets];
|
||||
}
|
||||
|
||||
//! during step2/pass2 all the applets with fills
|
||||
//! that remained with no computations from pass1
|
||||
//! are updated with the algorithm's proposed size
|
||||
function computeStep2ForLayout(layout, sizePerApplet, noOfApplets) {
|
||||
if (sizePerApplet>0) {
|
||||
if (noOfApplets === 0) {
|
||||
//! when all applets have assigned some size and there is still free space, we must find
|
||||
//! the most demanding space applet and assign the remaining space to it
|
||||
|
||||
var mostDemandingAppletSize = 0;
|
||||
var mostDemandingApplet = undefined;
|
||||
|
||||
//! applets with no strong opinion
|
||||
var neutralAppletsNo = 0;
|
||||
var neutralApplets = [];
|
||||
|
||||
for(var i=0; i<layout.children.length; ++i) {
|
||||
var curApplet = layout.children[i];
|
||||
|
||||
//! the most demanding applet is the one that has maximum size set to Infinity
|
||||
//! AND is not Neutral, meaning that it provided some valid metrics
|
||||
//! AND at the same time gained from step one the biggest space
|
||||
if (curApplet && curApplet.needsFillSpace && curApplet.applet && curApplet.applet.Layout) {
|
||||
var minSize = root.isVertical ? curApplet.applet.Layout.minimumHeight : curApplet.applet.Layout.minimumWidth;
|
||||
var prefSize = root.isVertical ? curApplet.applet.Layout.preferredHeight : curApplet.applet.Layout.preferredWidth;
|
||||
var maxSize = root.isVertical ? curApplet.applet.Layout.maximumHeight : curApplet.applet.Layout.maximumWidth;
|
||||
|
||||
var isNeutral = (minSize<=0 && prefSize<=0);
|
||||
|
||||
// console.log( " s4_0 " + curApplet.applet.pluginName + " : (" +minSize+","+prefSize+","+maxSize+") ");
|
||||
|
||||
if (!isNeutral && maxSize===Infinity && curApplet.sizeForFill>mostDemandingAppletSize) {
|
||||
mostDemandingApplet = curApplet;
|
||||
mostDemandingAppletSize = curApplet.sizeForFill;
|
||||
} else if (isNeutral) {
|
||||
neutralAppletsNo = neutralAppletsNo + 1;
|
||||
neutralApplets.push(curApplet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mostDemandingApplet) {
|
||||
//! the most demanding applet gains all the remaining space
|
||||
mostDemandingApplet.sizeForFill = mostDemandingApplet.sizeForFill + sizePerApplet;
|
||||
|
||||
// console.log("s4_1 "+ mostDemandingApplet.applet.pluginName + " assigned: " + mostDemandingApplet.sizeForFill + "\n");
|
||||
} else if (neutralAppletsNo>0) {
|
||||
//! if no demanding applets was found then the available space is splitted equally
|
||||
//! between all neutralApplets
|
||||
var adjustedAppletSize = (sizePerApplet / neutralAppletsNo);
|
||||
for (var j=0; j<neutralApplets.length; ++j) {
|
||||
// console.log("s4_2.0 "+ neutralApplets[j].applet.pluginName + " _ " + neutralApplets[j].sizeForFill + " _ " + adjustedAppletSize);
|
||||
|
||||
neutralApplets[j].sizeForFill = neutralApplets[j].sizeForFill + adjustedAppletSize;
|
||||
|
||||
// console.log("s4_2 "+ neutralApplets[j].applet.pluginName + " assigned: " + sizePerApplet + "\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(var i=0; i<layout.children.length; ++i) {
|
||||
var curApplet = layout.children[i];
|
||||
|
||||
if (curApplet && curApplet.needsFillSpace && curApplet.inFillCalculations) {
|
||||
curApplet.sizeForFill = sizePerApplet;
|
||||
// console.log("s4_3 "+ curApplet.applet.pluginName + " assigned: " + sizePerApplet + "\n");
|
||||
curApplet.inFillCalculations = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! initialize the three layouts and execute the step1/phase1
|
||||
//! it is used when the Centered (Main)Layout is used only or when the Main(Layout)
|
||||
//! is empty in Justify mode
|
||||
function initializationPhase(availableSpace, sizePerApplet, noOfApplets){
|
||||
if (root.panelAlignment === LatteCore.Types.Justify) {
|
||||
initLayoutForFillsCalculations(startLayout);
|
||||
initLayoutForFillsCalculations(endLayout);
|
||||
}
|
||||
initLayoutForFillsCalculations(mainLayout);
|
||||
|
||||
// console.log("s3...");
|
||||
|
||||
//! first pass in order to update sizes for applet that want to fill space
|
||||
//! but their maximum metrics are lower than the sizePerApplet
|
||||
var res = computeStep1ForLayout(mainLayout, availableSpace, sizePerApplet, noOfApplets);
|
||||
availableSpace = res[0]; sizePerApplet = res[1]; noOfApplets = res[2];
|
||||
|
||||
// console.log( " i1 : " + availableSpace + " _ " + sizePerApplet + " _ " + noOfApplets );
|
||||
|
||||
if (root.panelAlignment === LatteCore.Types.Justify) {
|
||||
res = computeStep1ForLayout(startLayout, availableSpace, sizePerApplet, noOfApplets);
|
||||
availableSpace = res[0]; sizePerApplet = res[1]; noOfApplets = res[2];
|
||||
// console.log( " i2 : " + availableSpace + " _ " + sizePerApplet + " _ " + noOfApplets );
|
||||
|
||||
res = computeStep1ForLayout(endLayout, availableSpace, sizePerApplet, noOfApplets);
|
||||
availableSpace = res[0]; sizePerApplet = res[1]; noOfApplets = res[2];
|
||||
// console.log( " i3 : " + availableSpace + " _ " + sizePerApplet + " _ " + noOfApplets );
|
||||
}
|
||||
|
||||
return [availableSpace, sizePerApplet, noOfApplets];
|
||||
}
|
||||
|
||||
|
||||
function updateSizeForAppletsInFill() {
|
||||
if (animations.inNormalFillCalculationsState) {
|
||||
// console.log("-------------");
|
||||
// console.log("s1...");
|
||||
var noA = startLayout.fillApplets + mainLayout.fillApplets + endLayout.fillApplets;
|
||||
|
||||
if (noA === 0)
|
||||
return;
|
||||
|
||||
// console.log("s2...");
|
||||
if (mainLayout.shownApplets === 0 || root.panelAlignment !== LatteCore.Types.Justify) {
|
||||
// console.log(" S2 _ SIZES ::: " + root.maxLength + " ___ " + startLayout.sizeWithNoFillApplets + " ___ " + mainLayout.sizeWithNoFillApplets + " ___ " + endLayout.sizeWithNoFillApplets);
|
||||
|
||||
var availableSpace = Math.max(0, root.maxLength - startLayout.sizeWithNoFillApplets - mainLayout.sizeWithNoFillApplets - endLayout.sizeWithNoFillApplets - root.panelEdgeSpacing);
|
||||
var sizePerApplet = availableSpace / noA;
|
||||
|
||||
var res = initializationPhase(availableSpace, sizePerApplet, noA);
|
||||
availableSpace = res[0]; sizePerApplet = res[1]; noA = res[2];
|
||||
|
||||
// console.log("s4...");
|
||||
|
||||
//! after step1 there is a chance that all applets were assigned a valid space
|
||||
//! but at the same time some space remained free. In such case we make sure
|
||||
//! that remained space will be assigned to the most demanding applet.
|
||||
//! This is achieved by <layout>No values. For step2 passing value!=0
|
||||
//! means default step2 behavior BUT value=0 means that remained space
|
||||
//! must be also assigned at the end.
|
||||
var remainedSpace = (noA === 0 && sizePerApplet > 0) ? true : false
|
||||
|
||||
var startNo = -1;
|
||||
var mainNo = -1;
|
||||
var endNo = -1;
|
||||
|
||||
if (remainedSpace) {
|
||||
if (startLayout.fillApplets > 0) {
|
||||
startNo = 0;
|
||||
} else if (endLayout.fillApplets > 0) {
|
||||
endNo = 0;
|
||||
} else if (mainLayout.fillApplets > 0) {
|
||||
mainNo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//! second pass in order to update sizes for applet that want to fill space
|
||||
//! these applets get the direct division of the available free space that
|
||||
//! remained from step1 OR the the free available space that no applet requested yet
|
||||
|
||||
computeStep2ForLayout(startLayout, sizePerApplet, startNo); //default behavior
|
||||
computeStep2ForLayout(mainLayout, sizePerApplet, mainNo); //default behavior
|
||||
computeStep2ForLayout(endLayout, sizePerApplet, endNo); //default behavior
|
||||
|
||||
//console.log("s5...");
|
||||
} else {
|
||||
//! Justify mode in all remaining cases
|
||||
|
||||
// console.log(" S3 _ SIZES ::: " + root.maxLength + " ___ " + startLayout.sizeWithNoFillApplets + " ___ " + mainLayout.sizeWithNoFillApplets + " ___ " + endLayout.sizeWithNoFillApplets);
|
||||
|
||||
//! compute the two free spaces around the centered layout
|
||||
//! they are called start and end accordingly
|
||||
var halfMainLayout = mainLayout.sizeWithNoFillApplets / 2;
|
||||
var availableSpaceStart = Math.max(0, root.maxLength/2 - startLayout.sizeWithNoFillApplets - halfMainLayout - root.panelEdgeSpacing/2);
|
||||
var availableSpaceEnd = Math.max(0, root.maxLength/2 - endLayout.sizeWithNoFillApplets - halfMainLayout - root.panelEdgeSpacing/2);
|
||||
var availableSpace = availableSpaceStart + availableSpaceEnd - mainLayout.sizeWithNoFillApplets;
|
||||
|
||||
var sizePerAppletMain = mainLayout.fillApplets > 0 ? availableSpace / noA : 0 ;
|
||||
|
||||
var noStart = startLayout.fillApplets;
|
||||
var noMain = mainLayout.fillApplets;
|
||||
var noEnd = endLayout.fillApplets;
|
||||
|
||||
//! initialize the computations
|
||||
initLayoutForFillsCalculations(startLayout);
|
||||
initLayoutForFillsCalculations(mainLayout);
|
||||
initLayoutForFillsCalculations(endLayout);
|
||||
|
||||
var res;
|
||||
|
||||
//! first pass
|
||||
if (mainLayout.fillApplets > 0){
|
||||
res = computeStep1ForLayout(mainLayout, availableSpace, sizePerAppletMain, noMain);
|
||||
sizePerAppletMain = res[1]; noMain = res[2];
|
||||
var dif = (availableSpace - res[0]) / 2;
|
||||
availableSpaceStart = availableSpaceStart - dif;
|
||||
availableSpaceEnd = availableSpaceEnd - dif;
|
||||
}
|
||||
|
||||
var sizePerAppletStart = startLayout.fillApplets > 0 ? availableSpaceStart / noStart : 0 ;
|
||||
var sizePerAppletEnd = endLayout.fillApplets > 0 ? availableSpaceEnd / noEnd : 0 ;
|
||||
|
||||
if (startLayout.fillApplets > 0) {
|
||||
res = computeStep1ForLayout(startLayout, availableSpaceStart, sizePerAppletStart, noStart);
|
||||
availableSpaceStart = res[0]; sizePerAppletStart = res[1]; noStart = res[2];
|
||||
}
|
||||
if (endLayout.fillApplets > 0) {
|
||||
res = computeStep1ForLayout(endLayout, availableSpaceEnd, sizePerAppletEnd, noEnd);
|
||||
availableSpaceEnd = res[0]; sizePerAppletEnd = res[1]; noEnd = res[2];
|
||||
}
|
||||
|
||||
////
|
||||
//! second pass
|
||||
|
||||
// console.log(" S ::: " +startLayout.fillApplets + " _ " + sizePerAppletStart + " _ " + noStart);
|
||||
|
||||
if (mainLayout.fillApplets > 0) {
|
||||
computeStep2ForLayout(mainLayout, sizePerAppletMain, noMain); //default behavior
|
||||
}
|
||||
|
||||
if (startLayout.fillApplets > 0) {
|
||||
computeStep2ForLayout(startLayout, sizePerAppletStart, noStart);
|
||||
}
|
||||
|
||||
if (endLayout.fillApplets > 0) {
|
||||
computeStep2ForLayout(endLayout, sizePerAppletEnd, noEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2020 Michail Vourlakos <mvourlakos@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.7
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
|
||||
import "./privates" as Ability
|
||||
|
||||
Ability.LayouterPrivate {
|
||||
id: _layouter
|
||||
|
||||
property bool appletsInParentChange: false
|
||||
|
||||
readonly property bool inNormalFillCalculationsState: animations.needBothAxis.count === 0
|
||||
&& animations.needThickness.count === 0
|
||||
&& ((animations.needLength.count === 0)
|
||||
|| (animations.needLength.count===1 && editModeVisual.inEditMode))
|
||||
&& (!dragOverlay || (dragOverlay && !dragOverlay.pressed)) /*do not update during moving/dragging applets*/
|
||||
&& !appletsInParentChange
|
||||
|
||||
|
||||
function updateSizeForAppletsInFill() {
|
||||
if (!updateSizeForAppletsInFillTimer.running) {
|
||||
_layouter._updateSizeForAppletsInFill();
|
||||
updateSizeForAppletsInFillTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
onInNormalFillCalculationsStateChanged: {
|
||||
if (inNormalFillCalculationsState) {
|
||||
_layouter.updateSizeForAppletsInFill();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: layouts
|
||||
onContentsLengthChanged: _layouter.updateSizeForAppletsInFill();
|
||||
|
||||
}
|
||||
|
||||
//! This timer is needed in order to reduce the calls to heavy cpu function
|
||||
//! updateSizeForAppletsInFill()
|
||||
Timer{
|
||||
id: updateSizeForAppletsInFillTimer
|
||||
interval: 50
|
||||
onTriggered: _layouter._updateSizeForAppletsInFill();
|
||||
}
|
||||
}
|
@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright 2020 Michail Vourlakos <mvourlakos@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.7
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
|
||||
import org.kde.latte.core 0.2 as LatteCore
|
||||
|
||||
import "./layouter" as LayouterElements
|
||||
|
||||
Item {
|
||||
property Item layouts: null
|
||||
property Item animations: null
|
||||
property Item indexer: null
|
||||
|
||||
readonly property int fillApplets: startLayout.fillApplets + mainLayout.fillApplets + endLayout.fillApplets
|
||||
|
||||
readonly property Item startLayout: LayouterElements.AppletsContainer {
|
||||
grid: layouts.startLayout
|
||||
}
|
||||
|
||||
readonly property Item mainLayout: LayouterElements.AppletsContainer {
|
||||
grid: layouts.mainLayout
|
||||
}
|
||||
|
||||
readonly property Item endLayout: LayouterElements.AppletsContainer {
|
||||
grid: layouts.endLayout
|
||||
}
|
||||
|
||||
//! FILLWIDTH/FILLHEIGHT COMPUTATIONS
|
||||
//! Computations in order to calculate correctly the sizes for applets
|
||||
//! that are requesting fillWidth or fillHeight
|
||||
|
||||
//! qBound style function that is specialized in Layouts
|
||||
//! meaning that -1 values are ignored for fillWidth(s)/Height(s)
|
||||
function layoutBound(min, pref, max){
|
||||
if (max === -1) {
|
||||
max = pref === -1 ? min : pref;
|
||||
}
|
||||
|
||||
if (pref === -1) {
|
||||
pref = max === -1 ? min : pref;
|
||||
}
|
||||
|
||||
return Math.min(Math.max(min,pref),max);
|
||||
}
|
||||
|
||||
|
||||
//! initialize AppletItems flag "inFillCalculations" in order
|
||||
//! to inform them that new calculations are taking place
|
||||
function initLayoutForFillsCalculations(layout) {
|
||||
for(var i=0; i<layout.children.length; ++i) {
|
||||
var curApplet = layout.children[i];
|
||||
if (curApplet.needsFillSpace) {
|
||||
curApplet.inFillCalculations = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! during step1/pass1 all applets that provide valid metrics (minimum/preferred/maximum values)
|
||||
//! they gain a valid space in order to draw themeselves
|
||||
function computeStep1ForLayout(layout, availableSpace, sizePerApplet, noOfApplets) {
|
||||
for(var i=0; i<layout.children.length; ++i) {
|
||||
var curApplet = layout.children[i];
|
||||
|
||||
if (curApplet.needsFillSpace) {
|
||||
if (curApplet && curApplet.applet && curApplet.applet.Layout) {
|
||||
var minSize = root.isVertical ? curApplet.applet.Layout.minimumHeight : curApplet.applet.Layout.minimumWidth;
|
||||
var prefSize = root.isVertical ? curApplet.applet.Layout.preferredHeight : curApplet.applet.Layout.preferredWidth;
|
||||
var maxSize = root.isVertical ? curApplet.applet.Layout.maximumHeight : curApplet.applet.Layout.maximumWidth;
|
||||
|
||||
// console.log( " s3_0 " + curApplet.applet.pluginName + " : (" +minSize+","+prefSize+","+maxSize+") ");
|
||||
|
||||
minSize = minSize>=0 && minSize!==Infinity ? minSize : -1;
|
||||
prefSize = minSize>=0 && prefSize!==Infinity ? prefSize : -1;
|
||||
maxSize = maxSize>=0 && maxSize!== Infinity ? maxSize : -1;
|
||||
|
||||
var appliedSize = -1;
|
||||
|
||||
//! check if the applet does not provide any valid metrics and for that case
|
||||
//! the system must decide what space to be given after the applets that provide
|
||||
//! nice metrics are assigned their sizes
|
||||
var systemDecide = ((minSize<0) && (prefSize<0) && (maxSize<0));
|
||||
|
||||
if (!systemDecide) {
|
||||
if (noOfApplets>1) {
|
||||
appliedSize = layoutBound(minSize, prefSize, maxSize);
|
||||
|
||||
// console.log( " s3_1 " + curApplet.applet.pluginName + " : (" +minSize+","+prefSize+","+maxSize+") -> " + appliedSize);
|
||||
} else if (noOfApplets===1) {
|
||||
//! at this step if only one applet has remained for which the max size is not null,
|
||||
//! then for this applet we make sure the maximum size does not exceed the available space
|
||||
//! in order for the applet to not be drawn outside the boundaries
|
||||
appliedSize = layoutBound(minSize, prefSize, Math.min(maxSize, sizePerApplet));
|
||||
|
||||
// console.log( " s3_2 " + curApplet.applet.pluginName + " : (" +minSize+","+prefSize+","+maxSize+") -> " + appliedSize);
|
||||
}
|
||||
|
||||
//! appliedSize is valid and is also lower than the availableSpace, if it is not lower then
|
||||
//! for this applet the needed space will be provided as a second pass in a fair way
|
||||
//! between all remained applets that did not gain a valid fill space
|
||||
if (appliedSize>=0 && appliedSize<=sizePerApplet) {
|
||||
var properSize = Math.min(appliedSize, availableSpace);
|
||||
var thickness = root.isVertical ? root.width : root.height;
|
||||
var adjustedSize = curApplet.isHidden ? 0 : Math.max(thickness, properSize);
|
||||
|
||||
curApplet.sizeForFill = adjustedSize;
|
||||
curApplet.inFillCalculations = false;
|
||||
availableSpace = Math.max(0, availableSpace - curApplet.sizeForFill);
|
||||
noOfApplets = noOfApplets - 1;
|
||||
sizePerApplet = noOfApplets > 1 ? Math.floor(availableSpace / noOfApplets) : availableSpace;
|
||||
|
||||
// console.log( " s3_3 " + curApplet.applet.pluginName + " assigned: " + curApplet.sizeForFill);
|
||||
}
|
||||
}
|
||||
|
||||
// console.log("s3_r " +curApplet.applet.pluginName + " : " + availableSpace + " _ " + sizePerApplet + " _ " + noOfApplets + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [availableSpace, sizePerApplet, noOfApplets];
|
||||
}
|
||||
|
||||
//! during step2/pass2 all the applets with fills
|
||||
//! that remained with no computations from pass1
|
||||
//! are updated with the algorithm's proposed size
|
||||
function computeStep2ForLayout(layout, sizePerApplet, noOfApplets) {
|
||||
if (sizePerApplet>0) {
|
||||
if (noOfApplets === 0) {
|
||||
//! when all applets have assigned some size and there is still free space, we must find
|
||||
//! the most demanding space applet and assign the remaining space to it
|
||||
|
||||
var mostDemandingAppletSize = 0;
|
||||
var mostDemandingApplet = undefined;
|
||||
|
||||
//! applets with no strong opinion
|
||||
var neutralAppletsNo = 0;
|
||||
var neutralApplets = [];
|
||||
|
||||
for(var i=0; i<layout.children.length; ++i) {
|
||||
var curApplet = layout.children[i];
|
||||
|
||||
//! the most demanding applet is the one that has maximum size set to Infinity
|
||||
//! AND is not Neutral, meaning that it provided some valid metrics
|
||||
//! AND at the same time gained from step one the biggest space
|
||||
if (curApplet && curApplet.needsFillSpace && curApplet.applet && curApplet.applet.Layout) {
|
||||
var minSize = root.isVertical ? curApplet.applet.Layout.minimumHeight : curApplet.applet.Layout.minimumWidth;
|
||||
var prefSize = root.isVertical ? curApplet.applet.Layout.preferredHeight : curApplet.applet.Layout.preferredWidth;
|
||||
var maxSize = root.isVertical ? curApplet.applet.Layout.maximumHeight : curApplet.applet.Layout.maximumWidth;
|
||||
|
||||
var isNeutral = (minSize<=0 && prefSize<=0);
|
||||
|
||||
// console.log( " s4_0 " + curApplet.applet.pluginName + " : (" +minSize+","+prefSize+","+maxSize+") ");
|
||||
|
||||
if (!isNeutral && maxSize===Infinity && curApplet.sizeForFill>mostDemandingAppletSize) {
|
||||
mostDemandingApplet = curApplet;
|
||||
mostDemandingAppletSize = curApplet.sizeForFill;
|
||||
} else if (isNeutral) {
|
||||
neutralAppletsNo = neutralAppletsNo + 1;
|
||||
neutralApplets.push(curApplet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mostDemandingApplet) {
|
||||
//! the most demanding applet gains all the remaining space
|
||||
mostDemandingApplet.sizeForFill = mostDemandingApplet.sizeForFill + sizePerApplet;
|
||||
|
||||
// console.log("s4_1 "+ mostDemandingApplet.applet.pluginName + " assigned: " + mostDemandingApplet.sizeForFill + "\n");
|
||||
} else if (neutralAppletsNo>0) {
|
||||
//! if no demanding applets was found then the available space is splitted equally
|
||||
//! between all neutralApplets
|
||||
var adjustedAppletSize = (sizePerApplet / neutralAppletsNo);
|
||||
for (var j=0; j<neutralApplets.length; ++j) {
|
||||
// console.log("s4_2.0 "+ neutralApplets[j].applet.pluginName + " _ " + neutralApplets[j].sizeForFill + " _ " + adjustedAppletSize);
|
||||
|
||||
neutralApplets[j].sizeForFill = neutralApplets[j].sizeForFill + adjustedAppletSize;
|
||||
|
||||
// console.log("s4_2 "+ neutralApplets[j].applet.pluginName + " assigned: " + sizePerApplet + "\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(var i=0; i<layout.children.length; ++i) {
|
||||
var curApplet = layout.children[i];
|
||||
|
||||
if (curApplet && curApplet.needsFillSpace && curApplet.inFillCalculations) {
|
||||
curApplet.sizeForFill = sizePerApplet;
|
||||
// console.log("s4_3 "+ curApplet.applet.pluginName + " assigned: " + sizePerApplet + "\n");
|
||||
curApplet.inFillCalculations = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! initialize the three layouts and execute the step1/phase1
|
||||
//! it is used when the Centered (Main)Layout is used only or when the Main(Layout)
|
||||
//! is empty in Justify mode
|
||||
function initializationPhase(availableSpace, sizePerApplet, noOfApplets){
|
||||
if (root.panelAlignment === LatteCore.Types.Justify) {
|
||||
initLayoutForFillsCalculations(startLayout.grid);
|
||||
initLayoutForFillsCalculations(endLayout.grid);
|
||||
}
|
||||
initLayoutForFillsCalculations(mainLayout.grid);
|
||||
|
||||
// console.log("s3...");
|
||||
|
||||
//! first pass in order to update sizes for applet that want to fill space
|
||||
//! but their maximum metrics are lower than the sizePerApplet
|
||||
var res = computeStep1ForLayout(mainLayout.grid, availableSpace, sizePerApplet, noOfApplets);
|
||||
availableSpace = res[0]; sizePerApplet = res[1]; noOfApplets = res[2];
|
||||
|
||||
// console.log( " i1 : " + availableSpace + " _ " + sizePerApplet + " _ " + noOfApplets );
|
||||
|
||||
if (root.panelAlignment === LatteCore.Types.Justify) {
|
||||
res = computeStep1ForLayout(startLayout.grid, availableSpace, sizePerApplet, noOfApplets);
|
||||
availableSpace = res[0]; sizePerApplet = res[1]; noOfApplets = res[2];
|
||||
// console.log( " i2 : " + availableSpace + " _ " + sizePerApplet + " _ " + noOfApplets );
|
||||
|
||||
res = computeStep1ForLayout(endLayout.grid, availableSpace, sizePerApplet, noOfApplets);
|
||||
availableSpace = res[0]; sizePerApplet = res[1]; noOfApplets = res[2];
|
||||
// console.log( " i3 : " + availableSpace + " _ " + sizePerApplet + " _ " + noOfApplets );
|
||||
}
|
||||
|
||||
return [availableSpace, sizePerApplet, noOfApplets];
|
||||
}
|
||||
|
||||
|
||||
function _updateSizeForAppletsInFill() {
|
||||
if (inNormalFillCalculationsState) {
|
||||
// console.log("-------------");
|
||||
// console.log("s1...");
|
||||
var noA = startLayout.fillApplets + mainLayout.fillApplets + endLayout.fillApplets;
|
||||
|
||||
if (noA === 0)
|
||||
return;
|
||||
|
||||
// console.log("s2...");
|
||||
if (mainLayout.shownApplets === 0 || root.panelAlignment !== LatteCore.Types.Justify) {
|
||||
// console.log(" S2 _ SIZES ::: " + root.maxLength + " ___ " + startLayout.sizeWithNoFillApplets + " ___ " + mainLayout.sizeWithNoFillApplets + " ___ " + endLayout.sizeWithNoFillApplets);
|
||||
|
||||
var availableSpace = Math.max(0, root.maxLength - startLayout.sizeWithNoFillApplets - mainLayout.sizeWithNoFillApplets - endLayout.sizeWithNoFillApplets - root.panelEdgeSpacing);
|
||||
var sizePerApplet = availableSpace / noA;
|
||||
|
||||
var res = initializationPhase(availableSpace, sizePerApplet, noA);
|
||||
availableSpace = res[0]; sizePerApplet = res[1]; noA = res[2];
|
||||
|
||||
// console.log("s4...");
|
||||
|
||||
//! after step1 there is a chance that all applets were assigned a valid space
|
||||
//! but at the same time some space remained free. In such case we make sure
|
||||
//! that remained space will be assigned to the most demanding applet.
|
||||
//! This is achieved by <layout>No values. For step2 passing value!=0
|
||||
//! means default step2 behavior BUT value=0 means that remained space
|
||||
//! must be also assigned at the end.
|
||||
var remainedSpace = (noA === 0 && sizePerApplet > 0) ? true : false
|
||||
|
||||
var startNo = -1;
|
||||
var mainNo = -1;
|
||||
var endNo = -1;
|
||||
|
||||
if (remainedSpace) {
|
||||
if (startLayout.fillApplets > 0) {
|
||||
startNo = 0;
|
||||
} else if (lendLayout.fillApplets > 0) {
|
||||
endNo = 0;
|
||||
} else if (mainLayout.fillApplets > 0) {
|
||||
mainNo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//! second pass in order to update sizes for applet that want to fill space
|
||||
//! these applets get the direct division of the available free space that
|
||||
//! remained from step1 OR the the free available space that no applet requested yet
|
||||
|
||||
computeStep2ForLayout(startLayout.grid, sizePerApplet, startNo); //default behavior
|
||||
computeStep2ForLayout(mainLayout.grid, sizePerApplet, mainNo); //default behavior
|
||||
computeStep2ForLayout(endLayout.grid, sizePerApplet, endNo); //default behavior
|
||||
|
||||
//console.log("s5...");
|
||||
} else {
|
||||
//! Justify mode in all remaining cases
|
||||
|
||||
// console.log(" S3 _ SIZES ::: " + root.maxLength + " ___ " + startLayout.sizeWithNoFillApplets + " ___ " + mainLayout.sizeWithNoFillApplets + " ___ " + endLayout.sizeWithNoFillApplets);
|
||||
|
||||
//! compute the two free spaces around the centered layout
|
||||
//! they are called start and end accordingly
|
||||
var halfMainLayout = mainLayout.sizeWithNoFillApplets / 2;
|
||||
var availableSpaceStart = Math.max(0, root.maxLength/2 - startLayout.sizeWithNoFillApplets - halfMainLayout - root.panelEdgeSpacing/2);
|
||||
var availableSpaceEnd = Math.max(0, root.maxLength/2 - endLayout.sizeWithNoFillApplets - halfMainLayout - root.panelEdgeSpacing/2);
|
||||
var availableSpace = availableSpaceStart + availableSpaceEnd - mainLayout.sizeWithNoFillApplets;
|
||||
|
||||
var sizePerAppletMain = mainLayout.fillApplets > 0 ? availableSpace / noA : 0 ;
|
||||
|
||||
var noStart = startLayout.fillApplets;
|
||||
var noMain = mainLayout.fillApplets;
|
||||
var noEnd = endLayout.fillApplets;
|
||||
|
||||
//! initialize the computations
|
||||
initLayoutForFillsCalculations(startLayout.grid);
|
||||
initLayoutForFillsCalculations(mainLayout.grid);
|
||||
initLayoutForFillsCalculations(endLayout.grid);
|
||||
|
||||
var res;
|
||||
|
||||
//! first pass
|
||||
if (mainLayout.fillApplets > 0){
|
||||
res = computeStep1ForLayout(mainLayout.grid, availableSpace, sizePerAppletMain, noMain);
|
||||
sizePerAppletMain = res[1]; noMain = res[2];
|
||||
var dif = (availableSpace - res[0]) / 2;
|
||||
availableSpaceStart = availableSpaceStart - dif;
|
||||
availableSpaceEnd = availableSpaceEnd - dif;
|
||||
}
|
||||
|
||||
var sizePerAppletStart = startLayout.fillApplets > 0 ? availableSpaceStart / noStart : 0 ;
|
||||
var sizePerAppletEnd = endLayout.fillApplets > 0 ? availableSpaceEnd / noEnd : 0 ;
|
||||
|
||||
if (startLayout.fillApplets > 0) {
|
||||
res = computeStep1ForLayout(startLayout.grid, availableSpaceStart, sizePerAppletStart, noStart);
|
||||
availableSpaceStart = res[0]; sizePerAppletStart = res[1]; noStart = res[2];
|
||||
}
|
||||
if (endLayout.fillApplets > 0) {
|
||||
res = computeStep1ForLayout(endLayout.grid, availableSpaceEnd, sizePerAppletEnd, noEnd);
|
||||
availableSpaceEnd = res[0]; sizePerAppletEnd = res[1]; noEnd = res[2];
|
||||
}
|
||||
|
||||
////
|
||||
//! second pass
|
||||
|
||||
// console.log(" S ::: " +startLayout.fillApplets + " _ " + sizePerAppletStart + " _ " + noStart);
|
||||
|
||||
if (mainLayout.fillApplets > 0) {
|
||||
computeStep2ForLayout(mainLayout.grid, sizePerAppletMain, noMain); //default behavior
|
||||
}
|
||||
|
||||
if (startLayout.fillApplets > 0) {
|
||||
computeStep2ForLayout(startLayout.grid, sizePerAppletStart, noStart);
|
||||
}
|
||||
|
||||
if (endLayout.fillApplets > 0) {
|
||||
computeStep2ForLayout(endLayout.grid, sizePerAppletEnd, noEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2020 Michail Vourlakos <mvourlakos@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.7
|
||||
|
||||
Item {
|
||||
id: appletsContainer
|
||||
|
||||
property Item grid: null
|
||||
|
||||
// items in grid
|
||||
readonly property int count: grid.children.length
|
||||
|
||||
//it is used in calculations for fillWidth,fillHeight applets
|
||||
property int shownApplets: 0
|
||||
property int fillApplets: 0
|
||||
|
||||
//it is used in calculations for fillWidth,fillHeight applets
|
||||
property int sizeWithNoFillApplets: 0
|
||||
|
||||
readonly property int maxIndex: 99999
|
||||
property int firstVisibleIndex: -1
|
||||
property int lastVisibleIndex: -1
|
||||
|
||||
//! do not update during dragging/moving applets inConfigureAppletsMode
|
||||
readonly property bool updateIsBlocked: (root.dragOverlay && root.dragOverlay.pressed) || appletsInParentChange
|
||||
|
||||
Binding{
|
||||
target: appletsContainer
|
||||
property:"sizeWithNoFillApplets"
|
||||
when: appletsContainer && grid && !updateIsBlocked && inNormalFillCalculationsState
|
||||
value: {
|
||||
var space = 0;
|
||||
for (var i=0; i<grid.children.length; ++i){
|
||||
if (grid.children[i]
|
||||
&& !grid.children[i].needsFillSpace
|
||||
&& !grid.children[i].isHidden) {
|
||||
space = root.isHorizontal ? space + grid.children[i].width : space + grid.children[i].height;
|
||||
}
|
||||
}
|
||||
|
||||
return space;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binding{
|
||||
target: appletsContainer
|
||||
property:"shownApplets"
|
||||
when: appletsContainer && grid && !updateIsBlocked
|
||||
value: {
|
||||
var res = 0;
|
||||
|
||||
for (var i=0; i<grid.children.length; ++i){
|
||||
if (grid.children[i] && grid.children[i].isHidden) {
|
||||
//do nothing
|
||||
} else if (grid.children[i] && (grid.children[i].applet || grid.children[i].isInternalViewSplitter)){
|
||||
res = res + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binding{
|
||||
target: appletsContainer
|
||||
property:"fillApplets"
|
||||
when: appletsContainer && grid && !updateIsBlocked
|
||||
value: {
|
||||
var no = 0;
|
||||
for (var i=0; i<grid.children.length; ++i){
|
||||
if (grid.children[i] && grid.children[i].needsFillSpace) {
|
||||
//console.log("fill :::: " + children[i].applet.pluginName);
|
||||
no++;
|
||||
}
|
||||
}
|
||||
|
||||
return no;
|
||||
}
|
||||
}
|
||||
|
||||
Binding{
|
||||
target: appletsContainer
|
||||
property:"firstVisibleIndex"
|
||||
when: appletsContainer && grid && !updateIsBlocked
|
||||
value: {
|
||||
var ind = maxIndex;
|
||||
for(var i=0; i<grid.children.length; ++i) {
|
||||
var appletItem = grid.children[i];
|
||||
if (appletItem && appletItem.index>=0
|
||||
&& indexer.hidden.indexOf(appletItem.index)<0
|
||||
&& indexer.separators.indexOf(appletItem.index)<0
|
||||
&& appletItem.index < ind) {
|
||||
ind = appletItem.index;
|
||||
}
|
||||
}
|
||||
|
||||
return ind === maxIndex ? -1 : ind;
|
||||
}
|
||||
}
|
||||
|
||||
Binding{
|
||||
target: appletsContainer
|
||||
property:"lastVisibleIndex"
|
||||
when: appletsContainer && grid && !updateIsBlocked
|
||||
value: {
|
||||
var ind = -1;
|
||||
for(var i=0; i<grid.children.length; ++i) {
|
||||
var appletItem = grid.children[i];
|
||||
if (appletItem && appletItem.index>=0
|
||||
&& indexer.hidden.indexOf(appletItem.index)<0
|
||||
&& indexer.separators.indexOf(appletItem.index)<0
|
||||
&& appletItem.index > ind) {
|
||||
ind = appletItem.index;
|
||||
}
|
||||
}
|
||||
|
||||
return ind;
|
||||
}
|
||||
}
|
||||
|
||||
onCountChanged: {
|
||||
if (root.editMode) {
|
||||
//! this is mainly used when removing/adding internal view splitters
|
||||
//! in order to not break the parabolic effect from wrong indexes
|
||||
root.updateIndexes();
|
||||
}
|
||||
}
|
||||
|
||||
onFillAppletsChanged: layouter.updateSizeForAppletsInFill();
|
||||
onShownAppletsChanged: layouter.updateSizeForAppletsInFill();
|
||||
onSizeWithNoFillAppletsChanged: {
|
||||
console.log(sizeWithNoFillApplets)
|
||||
layouter.updateSizeForAppletsInFill();
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue