Commit 0d133cf0 authored by Niccolò Venerandi's avatar Niccolò Venerandi
Browse files

Refactoring of qml/js side of the panel containment

parent 549ec82f
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2022 Niccolò Venerandi <niccolo@venerandi.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
......@@ -9,6 +10,7 @@ import QtQuick.Layouts 1.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kquickcontrolsaddons 2.0
......@@ -16,78 +18,19 @@ MouseArea {
id: configurationArea
z: 1000
anchors.fill: currentLayout
anchors.fill: parent
hoverEnabled: true
property bool isResizingLeft: false
property bool isResizingRight: false
property Item currentApplet
property int lastX
property int lastY
readonly property int spacerHandleSize: PlasmaCore.Units.smallSpacing
onHeightChanged: tooltip.visible = false;
onWidthChanged: tooltip.visible = false;
onPositionChanged: {
if (currentApplet && currentApplet.applet &&
currentApplet.applet.pluginName === "org.kde.plasma.panelspacer") {
if (plasmoid.formFactor === PlasmaCore.Types.Vertical) {
if ((mouse.y - handle.y) < spacerHandleSize ||
(mouse.y - handle.y) > (handle.height - spacerHandleSize)) {
configurationArea.cursorShape = Qt.SizeVerCursor;
} else {
configurationArea.cursorShape = Qt.ArrowCursor;
}
} else {
if ((mouse.x - handle.x) < spacerHandleSize ||
(mouse.x - handle.x) > (handle.width - spacerHandleSize)) {
configurationArea.cursorShape = Qt.SizeHorCursor;
} else {
configurationArea.cursorShape = Qt.ArrowCursor;
}
}
} else {
if (configurationArea.containsPress) {
configurationArea.cursorShape = Qt.ClosedHandCursor;
} else {
configurationArea.cursorShape = Qt.OpenHandCursor;
}
}
if (pressed) {
if (currentApplet && currentApplet.applet.pluginName === "org.kde.plasma.panelspacer") {
if (isResizingLeft) {
if (plasmoid.formFactor === PlasmaCore.Types.Vertical) {
handle.y += (mouse.y - lastY);
handle.height = currentApplet.height + (currentApplet.y - handle.y);
} else {
handle.x += (mouse.x - lastX);
handle.width = currentApplet.width + (currentApplet.x - handle.x);
}
lastX = mouse.x;
lastY = mouse.y;
return;
} else if (isResizingRight) {
if (plasmoid.formFactor === PlasmaCore.Types.Vertical) {
handle.height = mouse.y - handle.y;
} else {
handle.width = mouse.x - handle.x;
}
lastX = mouse.x;
lastY = mouse.y;
return;
}
}
// If the object has been dragged outside of the panel and there's
// a different containment there, we remove it from the panel
// containment and add it to the new one.
var padding = PlasmaCore.Units.gridUnit * 3;
if (currentApplet && (mouse.x < -padding || mouse.y < -padding ||
mouse.x > width + padding || mouse.y > height + padding)) {
......@@ -96,69 +39,56 @@ MouseArea {
if (newCont && newCont !== plasmoid) {
var newPos = newCont.mapFromApplet(plasmoid, mouse.x, mouse.y);
var applet = currentApplet.applet;
appletsModel.remove(placeHolder.parent.index);
currentApplet.destroy();
applet.anchors.fill = undefined
newCont.addApplet(applet, newPos.x, newPos.y);
return;
}
}
if (plasmoid.formFactor === PlasmaCore.Types.Vertical) {
currentApplet.y += (mouse.y - lastY);
handle.y = currentApplet.y;
} else {
currentApplet.x += (mouse.x - lastX);
handle.x = currentApplet.x;
}
lastX = mouse.x;
lastY = mouse.y;
var item = currentLayout.childAt(mouse.x, mouse.y);
if (item && item !== placeHolder) {
placeHolder.width = item.width;
placeHolder.height = item.height;
placeHolder.parent = configurationArea;
if (item && item.applet !== placeHolder) {
var posInItem = mapToItem(item, mouse.x, mouse.y);
let i = 0;
if ((plasmoid.formFactor === PlasmaCore.Types.Vertical && posInItem.y < item.height/2) ||
(plasmoid.formFactor !== PlasmaCore.Types.Vertical && posInItem.x < item.width/2)) {
i = root.layoutManager.insertBefore(item, placeHolder);
} else {
i = root.layoutManager.insertAfter(item, placeHolder);
if ((!root.isHorizontal && posInItem.y < item.height/3) ||
(root.isHorizontal && posInItem.x < item.width/3)) {
root.layoutManager.move(item, placeHolder.parent.index+1)
} else if ((!root.isHorizontal && posInItem.y > 2*item.height/3) ||
(root.isHorizontal && posInItem.x > 2*item.width/3)) {
root.layoutManager.move(item, placeHolder.parent.index)
}
if (i!=undefined) {root.layoutManager.updateMargins()}
}
} else {
var item = currentLayout.childAt(mouse.x, mouse.y);
if (root.dragOverlay && item && item !== lastSpacer) {
root.dragOverlay.currentApplet = item;
} else {
root.dragOverlay.currentApplet = null;
if (configurationArea && item) {
configurationArea.currentApplet = item;
}
}
if (root.dragOverlay.currentApplet) {
if (configurationArea.currentApplet) {
hideTimer.stop();
tooltip.visible = true;
tooltip.raise();
}
lastX = mouse.x;
lastY = mouse.y;
}
onEntered: hideTimer.stop();
onExited: hideTimer.restart()
onCurrentAppletChanged: {
if (!currentApplet || !root.dragOverlay.currentApplet) {
if (!currentApplet || !configurationArea.currentApplet) {
hideTimer.start();
return;
}
handle.x = currentApplet.x;
handle.y = currentApplet.y;
handle.width = currentApplet.width;
handle.height = currentApplet.height;
}
onPressed: {
......@@ -166,53 +96,19 @@ MouseArea {
// with with a touchscreen, because there are no entered events in that
// case
let item = currentLayout.childAt(mouse.x, mouse.y);
if (item) {
currentApplet = item;
root.dragOverlay.currentApplet = item;
tooltip.visible = true;
tooltip.raise();
hideTimer.stop();
}
if (!root.dragOverlay.currentApplet) {
return;
}
if (currentApplet.applet.pluginName === "org.kde.plasma.panelspacer") {
if (plasmoid.formFactor === PlasmaCore.Types.Vertical) {
if ((mouse.y - handle.y) < spacerHandleSize) {
configurationArea.isResizingLeft = true;
configurationArea.isResizingRight = false;
} else if ((mouse.y - handle.y) > (handle.height - spacerHandleSize)) {
configurationArea.isResizingLeft = false;
configurationArea.isResizingRight = true;
} else {
configurationArea.isResizingLeft = false;
configurationArea.isResizingRight = false;
}
} else {
if ((mouse.x - handle.x) < spacerHandleSize) {
configurationArea.isResizingLeft = true;
configurationArea.isResizingRight = false;
} else if ((mouse.x - handle.x) > (handle.width - spacerHandleSize)) {
configurationArea.isResizingLeft = false;
configurationArea.isResizingRight = true;
} else {
configurationArea.isResizingLeft = false;
configurationArea.isResizingRight = false;
}
}
}
lastX = mouse.x;
lastY = mouse.y;
placeHolder.width = currentApplet.width;
placeHolder.height = currentApplet.height;
placeHolder.dragging = currentApplet;
root.layoutManager.insertBefore(currentApplet, placeHolder);
currentApplet.parent = moveAppletLayer;
currentApplet.z = 900;
if (!item) {return}
tooltip.raise();
hideTimer.stop();
// We set the current applet being dragged as a property of placeHolder
// to be able to read its properties from the LayoutManager
appletsModel.insert(item.index, {applet: placeHolder});
placeHolder.parent.inThickArea = item.inThickArea
currentApplet = appletContainerComponent.createObject(root, {applet: item.applet, x: item.x, y: item.y, z: 900,
width: item.width, height: item.height, index: -1})
placeHolder.parent.dragging = currentApplet
appletsModel.remove(item.index)
root.dragAndDropping = true
}
onReleased: finishDragOperation()
......@@ -220,112 +116,64 @@ MouseArea {
onCanceled: finishDragOperation()
function finishDragOperation() {
root.dragAndDropping = false
if (!currentApplet) {
return;
}
if (plasmoid.formFactor === PlasmaCore.Types.Vertical) {
currentApplet.applet.configuration.length = handle.height;
} else {
currentApplet.applet.configuration.length = handle.width;
}
configurationArea.isResizingLeft = false;
configurationArea.isResizingRight = false;
root.layoutManager.insertBefore(placeHolder, currentApplet);
appletsModel.set(placeHolder.parent.index, {applet: currentApplet.applet})
let newCurrentApplet = currentApplet.applet.parent
newCurrentApplet.animateFrom(currentApplet.x, currentApplet.y)
newCurrentApplet.dragging = null
placeHolder.parent = configurationArea;
currentApplet.z = 1;
handle.x = currentApplet.x;
handle.y = currentApplet.y;
handle.width = currentApplet.width;
handle.height = currentApplet.height;
root.layoutManager.save();
currentApplet.destroy()
root.layoutManager.save()
}
Item {
id: placeHolder
property Item dragging
property bool busy: false
visible: configurationArea.containsMouse
Layout.preferredWidth: currentApplet ? currentApplet.Layout.preferredWidth : 0
Layout.preferredHeight: currentApplet ? currentApplet.Layout.preferredHeight : 0
Layout.maximumWidth: currentApplet ? currentApplet.Layout.maximumWidth : 0
Layout.maximumHeight: currentApplet ? currentApplet.Layout.maximumHeight : 0
Layout.minimumWidth: currentApplet ? currentApplet.Layout.minimumWidth : 0
Layout.minimumHeight: currentApplet ? currentApplet.Layout.minimumHeight : 0
Layout.fillWidth: currentApplet ? currentApplet.Layout.fillWidth : false
Layout.fillHeight: currentApplet ? currentApplet.Layout.fillHeight : false
}
Timer {
id: hideTimer
interval: PlasmaCore.Units.longDuration
onTriggered: tooltip.visible = false;
}
Connections {
target: currentApplet
function onXChanged() {handle.x = currentApplet.x}
function onYChanged() {handle.y = currentApplet.y}
function onWidthChanged() {handle.width = currentApplet.width}
function onHeightChanged() {handle.height = currentApplet.height}
interval: PlasmaCore.Units.longDuration * 5
onTriggered: currentApplet = null
}
Rectangle {
id: handle
visible: configurationArea.containsMouse
x: currentApplet ? currentApplet.x : NaN
y: currentApplet ? currentApplet.y : NaN
width: currentApplet ? currentApplet.width : NaN
height: currentApplet ? currentApplet.height : NaN
color: PlasmaCore.Theme.backgroundColor
radius: 3
opacity: currentApplet ? 0.5 : 0
opacity: currentApplet && configurationArea.containsMouse ? 0.5 : 0
PlasmaCore.IconItem {
visible: !root.dragAndDropping
source: "transform-move"
width: Math.min(parent.width, parent.height)
height: width
anchors.centerIn: parent
}
Rectangle {
anchors {
left: parent.left
top: parent.top
bottom: (plasmoid.formFactor !== PlasmaCore.Types.Vertical) ? parent.bottom : undefined
right: (plasmoid.formFactor !== PlasmaCore.Types.Vertical) ? undefined : parent.right
}
visible: currentApplet && currentApplet.applet.pluginName === "org.kde.plasma.panelspacer"
opacity: visible && !xAnim.running && !yAnim.running ? 1.0 : 0
width: configurationArea.spacerHandleSize
height: configurationArea.spacerHandleSize
color: PlasmaCore.Theme.textColor
Behavior on opacity {
NumberAnimation {
duration: PlasmaCore.Units.longDuration
easing.type: Easing.InOutQuad
}
}
}
Rectangle {
anchors {
right: parent.right
top: (plasmoid.formFactor !== PlasmaCore.Types.Vertical) ? parent.top : undefined
bottom: parent.bottom
left: (plasmoid.formFactor !== PlasmaCore.Types.Vertical) ? undefined : parent.left
}
visible: currentApplet && currentApplet.applet.pluginName === "org.kde.plasma.panelspacer"
opacity: visible && !xAnim.running && !yAnim.running ? 1.0 : 0
width: configurationArea.spacerHandleSize
height: configurationArea.spacerHandleSize
color: PlasmaCore.Theme.textColor
Behavior on opacity {
NumberAnimation {
duration: PlasmaCore.Units.longDuration
easing.type: Easing.InOutQuad
}
}
}
Behavior on x {
enabled: !configurationArea.pressed
NumberAnimation {
id: xAnim
duration: PlasmaCore.Units.longDuration
easing.type: Easing.InOutQuad
}
}
Behavior on y {
id: yAnim
enabled: !configurationArea.pressed
NumberAnimation {
duration: PlasmaCore.Units.longDuration
......@@ -355,6 +203,7 @@ MouseArea {
}
PlasmaCore.Dialog {
id: tooltip
visible: currentApplet && !root.dragAndDropping
visualParent: currentApplet
type: PlasmaCore.Dialog.Dock
......@@ -371,7 +220,7 @@ MouseArea {
}
mainItem: MouseArea {
enabled: currentApplet
enabled: tooltip.visible
width: handleButtons.width
height: handleButtons.height
hoverEnabled: true
......@@ -405,8 +254,8 @@ MouseArea {
iconSource: "delete"
text: i18n("Remove")
onClicked: {
tooltip.visible = false;
currentApplet.applet.action("remove").trigger();
currentApplet = null
}
}
PlasmaComponents.ToolButton {
......@@ -415,8 +264,8 @@ MouseArea {
iconSource: "configure"
text: i18n("Configure…")
onClicked: {
tooltip.visible = false;
currentApplet.applet.action("configure").trigger()
currentApplet = null
}
}
PlasmaComponents.ToolButton {
......@@ -425,8 +274,8 @@ MouseArea {
iconSource: "widget-alternatives"
text: i18n("Show Alternatives…")
onClicked: {
tooltip.visible = false;
currentApplet.applet.action("alternatives").trigger()
currentApplet = null
}
}
PlasmaComponents.ToolButton {
......@@ -440,8 +289,31 @@ MouseArea {
iconSource: "delete"
text: i18n("Remove")
onClicked: {
tooltip.visible = false;
currentApplet.applet.action("remove").trigger();
currentApplet.applet.action("remove").trigger()
currentApplet = null
}
}
PlasmaExtras.Heading {
Layout.fillWidth: true
visible: panelSpacerWidth.visible
text: i18n("Spacer width")
level: 3
horizontalAlignment: Text.AlignHCenter
}
PlasmaComponents3.SpinBox {
id: panelSpacerWidth
editable: true
Layout.fillWidth: true
focus: !Kirigami.InputMethod.willShowOnActive
visible: currentApplet && currentApplet.applet.pluginName === "org.kde.plasma.panelspacer" && !currentApplet.applet.configuration.expanding
from: 0
stepSize: 10
to: root.width
value: currentApplet && currentApplet.applet.configuration.length ? currentApplet.applet.configuration.length : 0
onValueModified: {
currentApplet.applet.configuration.length = value
}
}
}
......
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2022 Niccolò Venerandi <niccolo@venerandi.com>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
......@@ -7,9 +8,46 @@
var layout;
var root;
var plasmoid;
var lastSpacer;
var marginHighlights;
var appletsModel;
function addApplet(applet, x, y) {
// don't show applet if it chooses to be hidden but still make it
// accessible in the panelcontroller
// Due to the nature of how "visible" propagates in QML, we need to
// explicitly set it on the container (so the Layout ignores it)
// as well as the applet (so it reliably knows about), otherwise it can
// happen that an applet erroneously thinks it's visible, or suddenly
// starts thinking that way on teardown (virtual desktop pager)
// leading to crashes
var new_element = {applet: applet}
applet.visible = Qt.binding(function() {
return applet.status !== PlasmaCore.Types.HiddenStatus || (!plasmoid.immutable && plasmoid.userConfiguring);
});
if (x >= 0 && y >= 0) {
appletsModel.insert(indexAtCoordinates(x, y), new_element)
// Insert icons to the left of whatever is at the center (usually a Task Manager),
// if it exists.
// FIXME TODO: This is a real-world fix to produce a sensible initial position for
// launcher icons added by launcher menu applets. The basic approach has been used
// since Plasma 1. However, "add launcher to X" is a generic-enough concept and
// frequent-enough occurrence that we'd like to abstract it further in the future
// and get rid of the ugliness of parties external to the containment adding applets
// of a specific type, and the containment caring about the applet type. In a better
// system the containment would be informed of requested launchers, and determine by
// itself what it wants to do with that information.
} else if (applet.pluginName === "org.kde.plasma.icon" &&
(middle = currentLayout.childAt(root.width / 2, root.height / 2))) {
appletsModel.insert(middle.index, new_element);
// Fall through to determining an appropriate insert position.
} else {
appletsModel.append(new_element);
}
updateMargins();
}
function restore() {
var configString = String(plasmoid.configuration.AppletOrder)
......@@ -39,7 +77,7 @@ function restore() {
//finally, restore the applets in the correct order
for (var i in appletsOrder) {
root.addApplet(appletsOrder[i], -1, -1)
addApplet(appletsOrder[i], -1, -1)
}
//rewrite, so if in the orders there were now invalid ids or if some were missing creates a correct list instead
save();
......@@ -54,187 +92,54 @@ function save() {
ids.push(child.applet.id);
}
}
plasmoid.configuration.AppletOrder = ids.join(';');
updateMargins();
}
function removeApplet (applet) {
for (var i = layout.children.length - 1; i >= 0; --i) {
var child = layout.children[i];
if (child.applet === applet) {
// This makes sure the child is not in the layout.children anymore
// even while it's being destroyed.
child.parent = root;
child.destroy();
}
}
}
//insert item2 before item1
function insertBefore(item1, item2) {
if (item1 === item2) {
return;
}
var removed = new Array();
var child;
var i;
for (i = layout.children.length - 1; i >= 0; --i) {
child = layout.children[i];
removed.push(child);
child.parent = root;
if (child === item1) {
break;
}
}
item2.parent = layout;
for (var j = removed.length - 1; j >= 0; --j) {
removed[j].parent = layout;
}
return i;
}
//insert item2 after item1
function insertAfter(item1, item2) {
if (item1 === item2) {
return;
}
var removed = new Array();
var child;
var i;
for (i = layout.children.length - 1; i >= 0; --i) {
child = layout.children[i];
//never ever insert after lastSpacer
if (child === item1) {
//Already in position, do nothing
if (layout.children[i+1] === item2) {
return;
}
break;