File indexing completed on 2024-11-24 05:00:31

0001 /*
0002     SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
0003     SPDX-FileCopyrightText: 2022 Niccolò Venerandi <niccolo@venerandi.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 var layout;
0009 var root;
0010 var plasmoid;
0011 var marginHighlights;
0012 var appletsModel;
0013 
0014 function addApplet(applet, x, y) {
0015     let appletItem = root.itemFor(applet);
0016     // don't show applet if it chooses to be hidden but still make it
0017     // accessible in the panelcontroller
0018     // Due to the nature of how "visible" propagates in QML, we need to
0019     // explicitly set it on the container (so the Layout ignores it)
0020     // as well as the applet (so it reliably knows about), otherwise it can
0021     // happen that an applet erroneously thinks it's visible, or suddenly
0022     // starts thinking that way on teardown (virtual desktop pager)
0023     // leading to crashes
0024     var middle, new_element = {applet: appletItem}
0025 
0026     appletItem.visible = Qt.binding(function() {
0027         return applet.status !== PlasmaCore.Types.HiddenStatus || (!root.plasmoid.immutable && root.plasmoid.userConfiguring);
0028     });
0029 
0030     // Insert icons to the left of whatever is at the center (usually a Task Manager),
0031     // if it exists.
0032     // FIXME TODO: This is a real-world fix to produce a sensible initial position for
0033     // launcher icons added by launcher menu applets. The basic approach has been used
0034     // since Plasma 1. However, "add launcher to X" is a generic-enough concept and
0035     // frequent-enough occurrence that we'd like to abstract it further in the future
0036     // and get rid of the ugliness of parties external to the containment adding applets
0037     // of a specific type, and the containment caring about the applet type. In a better
0038     // system the containment would be informed of requested launchers, and determine by
0039     // itself what it wants to do with that information.
0040     if (applet.pluginName === "org.kde.plasma.icon" && x === 0 && y === 0 &&
0041             (middle = currentLayout.childAt(root.width / 2, root.height / 2))) {
0042         appletsModel.insert(middle.index, new_element);
0043     // Fall through to determining an appropriate insert position.
0044     } else if (x >= 0 && y >= 0) {
0045         appletsModel.insert(indexAtCoordinates(x, y), new_element)
0046     } else {
0047         appletsModel.append(new_element);
0048     }
0049     updateMargins();
0050 }
0051 
0052 function restore() {
0053     var configString = String(root.plasmoid.configuration.AppletOrder)
0054 
0055     //array, a cell for encoded item order
0056     var itemsArray = configString.split(";");
0057 
0058     //map applet id->order in panel
0059     var idsOrder = new Object();
0060     //map order in panel -> applet pointer
0061     var appletsOrder = new Object();
0062 
0063     for (var i = 0; i < itemsArray.length; i++) {
0064         //property name: applet id
0065         //property value: order
0066         idsOrder[itemsArray[i]] = i;
0067     }
0068 
0069     for (var i = 0; i < root.plasmoid.applets.length; ++i) {
0070         if (idsOrder[root.plasmoid.applets[i].id] !== undefined) {
0071             appletsOrder[idsOrder[root.plasmoid.applets[i].id]] = root.plasmoid.applets[i];
0072         //ones that weren't saved in AppletOrder go to the end
0073         } else {
0074             appletsOrder["unordered"+i] = root.plasmoid.applets[i];
0075         }
0076     }
0077 
0078     //finally, restore the applets in the correct order
0079     for (var i in appletsOrder) {
0080         addApplet(appletsOrder[i], -1, -1)
0081     }
0082     //rewrite, so if in the orders there were now invalid ids or if some were missing creates a correct list instead
0083     save();
0084 }
0085 
0086 function save() {
0087     var ids = new Array();
0088     for (var i = 0; i < layout.children.length; ++i) {
0089         var child = layout.children[i];
0090         if (child.hasOwnProperty("applet") && child.applet) {
0091             ids.push(child.applet.plasmoid.id);
0092         }
0093     }
0094     root.plasmoid.configuration.AppletOrder = ids.join(';');
0095     root.plasmoid.configuration.writeConfig();
0096     updateMargins();
0097 }
0098 
0099 function childAtCoordinates(x, y) {
0100     if (root.isHorizontal) {
0101         y = layout.height / 2;
0102     } else {
0103         x = layout.width / 2;
0104     }
0105     /*
0106      * When adding a new panel, childAt will return lastSpacer, and that's where
0107      * `index` property works.
0108      */
0109     var child = layout.childAt(x, y);
0110     while (!child) {
0111         if (root.isHorizontal) {
0112             // Only yields incorrect results for widgets smaller than the
0113             // row/column spacing, which is luckly fairly unrealistic
0114             x -= layout.rowSpacing
0115         } else {
0116             y -= layout.columnSpacing
0117         }
0118         if (x < 0 || y < 0) {
0119             return 0;
0120         }
0121         child = layout.childAt(x, y);
0122     }
0123     return child
0124 }
0125 
0126 function indexAtCoordinates(x, y) {
0127     let child = childAtCoordinates(x, y)
0128     if ((root.plasmoid.formFactor === 3 && y < child.y + child.height/2) ||
0129         (root.plasmoid.formFactor !== 3 && x < child.x + child.width/2)) {
0130         return child.index;
0131     } else {
0132         return child.index+1;
0133     }
0134 }
0135 
0136 function updateMargins() {
0137     var inThickArea = false;
0138     for (var i = 0; i < appletsModel.count; ++i) {
0139         var child = appletsModel.get(i).applet.parent
0140         if (child.dragging) {child = child.dragging}
0141         child.inThickArea = inThickArea
0142         if (child.isMarginSeparator) {
0143             inThickArea = !inThickArea
0144         }
0145     }
0146 }
0147 
0148 function move(applet, end) {
0149     var start = applet.index
0150     var target = end - (start < end)
0151     if (start == target) return;
0152     // Setting oldX,oldY allows for position animations
0153     for (let i = Math.min(start, end); i <= Math.max(start, end-1); i++) {
0154         let el = layout.children[i]
0155         el.oldX = el.x, el.oldY = el.y
0156     }
0157     appletsModel.move(start, target, 1)
0158     save()
0159 }