You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
latte-dock/containment/package/contents/ui/abilities/AutoSize.qml

263 lines
9.4 KiB
QML

/*
SPDX-FileCopyrightText: 2019 Michail Vourlakos <mvourlakos@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.8
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.latte.core 0.2 as LatteCore
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.behaveAsDockWithMask
&& plasmoid.configuration.autoSizeEnabled
&& !root.containsOnlyPlasmaTasks
&& layouter.fillApplets<=0
&& !(root.inConfigureAppletsMode && plasmoid.configuration.alignment === LatteCore.Types.Justify) /*block shrinking for justify splitters*/
&& latteView
&& latteView.visibility.mode !== LatteCore.Types.SidebarOnDemand
&& latteView.visibility.mode !== LatteCore.Types.SidebarAutoHide
property int iconSize: -1 //it is not set, this is the default
readonly property bool inCalculatedIconSize: ((metrics.iconSize === sizer.iconSize) || (metrics.iconSize === metrics.maxIconSize))
readonly property bool inAutoSizeAnimation: !inCalculatedIconSize
readonly property int automaticStep: 8
readonly property int historyMaxSize: 10
readonly property int historyMinSize: 4
//! Prediction History of the algorithm in order to track cases where the algorithm produces
//! grows and shrinks endlessly
property variant history: []
//! required elements
property Item layouts
property Item layouter
property Item metrics
property Item visibility
onInAutoSizeAnimationChanged: {
if (inAutoSizeAnimation) {
animations.needBothAxis.addEvent(sizer);
} else {
animations.needBothAxis.removeEvent(sizer);
}
}
onIsActiveChanged: {
clearHistory();
updateIconSize();
}
Connections {
target: root
onContainsOnlyPlasmaTasksChanged: sizer.updateIconSize();
onMaxLengthChanged: {
fix #96,FEATURE:AllScreens and AllSecondaryScreens --This is a HUGE FEATURE and so important for multi-screens users. It is introduced as one single commit because it reimplements plenty of infrastructure changes and it will be easier to identify newly introduced bugs. --Users can now choose for their docks and panels to belong at various screen groups. The first two screen groups introduced are AllScreens and AllSecondayScreens. In the future it might be possible to provide CustomScreensGroup that the user will be able to define specific screens in which a dock or panel should be always present. --Current solution specifies an Original dock or panel and clones/copies itself automatically to other screens. So docks and panels in other screens are just real docks and panels that reference themselves to original docks and panels. --Clones are destroyed during layout startup and are automaticaly recreated. It is suggested to export your layouts through the official Layouts Editor in order to share them because in that case clones are not included in the new generated layout file. If in any case you do not this and you share your layout with any previous versions then your clones will just appear as separate docks and panels that belong to specific screens. --Automatic syncing was introduced in order to keep up-to-date the configuration of Original docks and panels with their referenced Clones. --Automatic syncing currently works for all docks and panels settings, for all normal applets configurations and for all subcontaiments configuration such as systrays. --Automatic syncing does not work for applets inside subcontainments such as Group Plasmoid. In such case it is suggested to configure your applets inside your Group Plasmoid in the original dock or panel and afterwards to trigger a recreation for the relevant clones --Manual recreation of clones is easily possible by just choosing the dock or panel to be OnPrimary or OnSpecificScreen and rechoosing afterwards the AllScreensGroup or AllSecondaryScreensGroup
3 years ago
if (latteView && latteView.positioner && !latteView.positioner.isOffScreen) {
sizer.updateIconSize();
}
}
}
Connections {
target: metrics
onPortionIconSizeChanged: {
if (metrics.portionIconSize!==-1) {
sizer.updateIconSize();
}
}
}
Connections {
target: latteView
onWidthChanged:{
if (root.isHorizontal && metrics.portionIconSize!==-1) {
sizer.updateIconSize();
}
}
onHeightChanged:{
if (root.isVertical && metrics.portionIconSize!==-1) {
sizer.updateIconSize();
}
}
}
fix #96,FEATURE:AllScreens and AllSecondaryScreens --This is a HUGE FEATURE and so important for multi-screens users. It is introduced as one single commit because it reimplements plenty of infrastructure changes and it will be easier to identify newly introduced bugs. --Users can now choose for their docks and panels to belong at various screen groups. The first two screen groups introduced are AllScreens and AllSecondayScreens. In the future it might be possible to provide CustomScreensGroup that the user will be able to define specific screens in which a dock or panel should be always present. --Current solution specifies an Original dock or panel and clones/copies itself automatically to other screens. So docks and panels in other screens are just real docks and panels that reference themselves to original docks and panels. --Clones are destroyed during layout startup and are automaticaly recreated. It is suggested to export your layouts through the official Layouts Editor in order to share them because in that case clones are not included in the new generated layout file. If in any case you do not this and you share your layout with any previous versions then your clones will just appear as separate docks and panels that belong to specific screens. --Automatic syncing was introduced in order to keep up-to-date the configuration of Original docks and panels with their referenced Clones. --Automatic syncing currently works for all docks and panels settings, for all normal applets configurations and for all subcontaiments configuration such as systrays. --Automatic syncing does not work for applets inside subcontainments such as Group Plasmoid. In such case it is suggested to configure your applets inside your Group Plasmoid in the original dock or panel and afterwards to trigger a recreation for the relevant clones --Manual recreation of clones is easily possible by just choosing the dock or panel to be OnPrimary or OnSpecificScreen and rechoosing afterwards the AllScreensGroup or AllSecondaryScreensGroup
3 years ago
Connections {
target: latteView && latteView.positioner ? latteView.positioner : null
onIsOffScreenChanged: {
if (!latteView.positioner.isOffScreen) {
sizer.updateIconSize();
}
}
}
Connections {
target: visibilityManager
onInNormalStateChanged: {
if (visibilityManager.inNormalState) {
sizer.updateIconSize();
}
}
}
//! 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<history.length; ++i) {
console.log( i + ". " + history[i].current + " : " + history[i].predicted);
}*/
if (history.length > 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 updateIconSize() {
if (!isActive && iconSize !== -1) {
// restore original icon size
iconSize = -1;
}
if ( !doubleCallAutomaticUpdateIconSize.running && !visibility.inRelocationHiding /*block too many calls and dont apply during relocatinon hiding*/
&& (visibility.inNormalState && sizer.isActive) /*in normal and auto size active state*/
&& (metrics.iconSize===metrics.maxIconSize || metrics.iconSize === sizer.iconSize) /*not during animations*/) {
//!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.alignment === LatteCore.Types.Justify) ?
layouts.startLayout.height+layouts.mainLayout.height+layouts.endLayout.height : layouts.mainLayout.height
} else {
layoutLength = (plasmoid.configuration.alignment === LatteCore.Types.Justify) ?
layouts.startLayout.width+layouts.mainLayout.width+layouts.endLayout.width : layouts.mainLayout.width
}
var itemLength = metrics.totals.length;
var toShrinkLimit = maxLength - (parabolic.factor.zoom * 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 * parabolic.factor.zoom * itemLength);
//console.log("toShrinkLimit: "+ toShrinkLimit);
//console.log("toGrowLimit: "+ toGrowLimit);
var newIconSizeFound = false;
if (layoutLength > toShrinkLimit) { //must shrink
// console.log("step3");
var nextIconSize = metrics.maxIconSize;
do {
nextIconSize = nextIconSize - automaticStep;
var factor = nextIconSize / metrics.iconSize;
var nextLength = factor * layoutLength;
} while ( (nextLength>toShrinkLimit) && (nextIconSize !== 16));
var intLength = Math.round(layoutLength);
var intNextLength = Math.round(nextLength);
iconSize = nextIconSize;
newIconSizeFound = true;
addPrediction(intLength, intNextLength);
// console.log("Step 3 - found:"+iconSize);
} else if ((layoutLength<toGrowLimit
&& (metrics.iconSize === iconSize)) ) { //must grow probably
// console.log("step4");
var nextIconSize2 = iconSize;
var foundGoodSize = -1;
do {
nextIconSize2 = nextIconSize2 + automaticStep;
var factor2 = nextIconSize2 / iconSize;
var nextLength2 = factor2 * layoutLength;
if (nextLength2 < toGrowLimit) {
foundGoodSize = nextIconSize2;
}
} while ( (nextLength2<toGrowLimit) && (nextIconSize2 !== metrics.maxIconSize ));
var intLength2 = Math.round(layoutLength);
var intNextLength2 = Math.round(nextLength2);
if (foundGoodSize > 0 && !producesEndlessLoop(intLength2, intNextLength2)) {
if (foundGoodSize === metrics.maxIconSize) {
iconSize = -1;
} else {
iconSize = foundGoodSize;
}
newIconSizeFound = true
addPrediction(intLength2, intNextLength2);
// console.log("Step 4 - found:"+iconSize);
} else {
// console.log("Step 4 - did not found...");
}
}
}
}
//! This functions makes sure to call the updateIconSize(); 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.updateIconSize();
}
}
}
}