Warning, /plasma/plasma-desktop/containments/desktop/package/contents/ui/ConfigOverlay.qml is written in an unsupported language. File is not indexed.

0001 /*
0002     SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 import QtQuick 2.15
0008 import QtQuick.Layouts 1.15
0009 
0010 import org.kde.plasma.plasmoid 2.0
0011 import org.kde.plasma.core as PlasmaCore
0012 import org.kde.kirigami 2.20 as Kirigami
0013 import org.kde.ksvg 1.0 as KSvg
0014 
0015 
0016 import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager
0017 
0018 ContainmentLayoutManager.ConfigOverlayWithHandles {
0019     id: overlay
0020 
0021     SequentialAnimation {
0022         id: removeAnim
0023 
0024         NumberAnimation {
0025             target: overlay.itemContainer
0026             property: "scale"
0027             from: 1
0028             to: 0
0029             duration: Kirigami.Units.longDuration
0030             easing.type: Easing.InOutQuad
0031         }
0032         ScriptAction {
0033             script: {
0034                 appletContainer.applet.plasmoid.internalAction("remove").trigger();
0035                 appletContainer.editMode = false;
0036             }
0037         }
0038     }
0039 
0040     KSvg.FrameSvgItem {
0041         id: frame
0042 
0043         anchors.verticalCenter: parent.verticalCenter
0044         x: overlay.rightAvailableSpace > width + Kirigami.Units.gridUnit
0045             ? parent.width + Kirigami.Units.gridUnit
0046             : -width - Kirigami.Units.gridUnit
0047 
0048         // This MouseArea is used to block input between the applet and the handle, to not make it steal by other applets
0049         MouseArea {
0050             anchors {
0051                 top: parent.top
0052                 bottom: parent.bottom
0053             }
0054             z: -1
0055             x: overlay.rightAvailableSpace > parent.width + Kirigami.Units.gridUnit ? -Kirigami.Units.gridUnit : 0
0056             width: Kirigami.Units.gridUnit + parent.width
0057             hoverEnabled: true
0058         }
0059         transform: Translate {
0060             x: open ? 0 : (overlay.rightAvailableSpace > frame.width + Kirigami.Units.gridUnit ? -frame.width : frame.width)
0061 
0062             Behavior on x {
0063                 NumberAnimation {
0064                     duration: Kirigami.Units.longDuration
0065                     easing.type: Easing.InOutQuad
0066                 }
0067             }
0068         }
0069         width: layout.implicitWidth + margins.left + margins.right
0070         height: Math.max(layout.implicitHeight + margins.top + margins.bottom, parent.height)
0071         imagePath: "widgets/background"
0072 
0073         ColumnLayout {
0074             id: layout
0075             anchors {
0076                 fill: parent
0077                 topMargin: parent.margins.top
0078                 leftMargin: parent.margins.left
0079                 bottomMargin: parent.margins.bottom
0080                 rightMargin: parent.margins.right
0081             }
0082 
0083             ActionButton {
0084                 id: rotateButton
0085                 icon.name: "object-rotate-left-symbolic"
0086                 toolTip: !rotateHandle.pressed ? i18n("Click and drag to rotate") : ""
0087                 action: applet ? applet.plasmoid.internalAction("rotate") : null
0088                 down: rotateHandle.pressed
0089                 Component.onCompleted: {
0090                     if (action !== null) {
0091                         action.enabled = true;
0092                     }
0093                 }
0094                 MouseArea {
0095                     id: rotateHandle
0096                     anchors.fill: parent
0097 
0098                     property int startRotation
0099                     property real startCenterRelativeAngle
0100 
0101                     function pointAngle(pos: point): real {
0102                         var r = Math.sqrt(pos.x * pos.x + pos.y * pos.y);
0103                         var cosine = pos.x / r;
0104 
0105                         if (pos.y >= 0) {
0106                             return Math.acos(cosine) * (180/Math.PI);
0107                         } else {
0108                             return -Math.acos(cosine) * (180/Math.PI);
0109                         }
0110                     }
0111 
0112                     function centerRelativePos(x: real, y: real): point {
0113                         var mousePos = overlay.itemContainer.parent.mapFromItem(rotateButton, x, y);
0114                         var centerPos = overlay.itemContainer.parent.mapFromItem(overlay.itemContainer, overlay.itemContainer.width/2, overlay.itemContainer.height/2);
0115 
0116                         mousePos.x -= centerPos.x;
0117                         mousePos.y -= centerPos.y;
0118                         return mousePos;
0119                     }
0120 
0121                     onPressed: mouse => {
0122                         mouse.accepted = true;
0123                         startRotation = overlay.itemContainer.rotation;
0124                         startCenterRelativeAngle = pointAngle(centerRelativePos(mouse.x, mouse.y));
0125                     }
0126 
0127                     onPositionChanged: mouse => {
0128                         var rot = startRotation % 360;
0129                         var snap = 4;
0130                         var newRotation = Math.round(pointAngle(centerRelativePos(mouse.x, mouse.y)) - startCenterRelativeAngle + startRotation);
0131 
0132                         if (newRotation < 0) {
0133                             newRotation = newRotation + 360;
0134                         } else if (newRotation >= 360) {
0135                             newRotation = newRotation % 360;
0136                         }
0137 
0138                         snapIt(0);
0139                         snapIt(90);
0140                         snapIt(180);
0141                         snapIt(270);
0142 
0143                         function snapIt(snapTo) {
0144                             if (newRotation > (snapTo - snap) && newRotation < (snapTo + snap)) {
0145                                 newRotation = snapTo;
0146                             }
0147                         }
0148 
0149                         overlay.itemContainer.rotation = newRotation;
0150                     }
0151 
0152                     onReleased: mouse => {
0153                         // save rotation
0154                         appletsLayout.save();
0155                     }
0156                 }
0157             }
0158 
0159             ActionButton {
0160                 icon.name: "configure"
0161                 visible: qAction && qAction.enabled && (applet && applet.plasmoid.hasConfigurationInterface)
0162                 qAction: applet ? applet.plasmoid.internalAction("configure") : null
0163                 Component.onCompleted: {
0164                     if (qAction) {
0165                         qAction.enabled = true;
0166                     }
0167                 }
0168             }
0169 
0170             ActionButton {
0171                 // FIXME: missing from Breeze icons! See
0172                 // https://bugs.kde.org/show_bug.cgi?id=472863.
0173                 icon.name: "showbackground"
0174                 toolTip: checked ? i18n("Hide Background") : i18n("Show Background")
0175                 visible: (applet.plasmoid.backgroundHints & PlasmaCore.Types.ConfigurableBackground)
0176                 checked: applet.plasmoid.effectiveBackgroundHints & PlasmaCore.Types.StandardBackground || applet.plasmoid.effectiveBackgroundHints & PlasmaCore.Types.TranslucentBackground
0177                 checkable: true
0178                 onClicked: {
0179                     if (checked) {
0180                         if (applet.plasmoid.backgroundHints & PlasmaCore.Types.StandardBackground || applet.plasmoid.backgroundHints & PlasmaCore.Types.TranslucentBackground) {
0181                             applet.plasmoid.userBackgroundHints = applet.plasmoid.backgroundHints;
0182                         } else {
0183                             applet.plasmoid.userBackgroundHints = PlasmaCore.Types.StandardBackground;
0184                         }
0185                     } else {
0186                         if (applet.plasmoid.backgroundHints & PlasmaCore.Types.ShadowBackground || applet.plasmoid.backgroundHints & PlasmaCore.Types.NoBackground) {
0187                             applet.plasmoid.userBackgroundHints = applet.plasmoid.backgroundHints;
0188                         } else {
0189                             applet.plasmoid.userBackgroundHints = PlasmaCore.Types.ShadowBackground;
0190                         }
0191                     }
0192                 }
0193             }
0194 
0195             MouseArea {
0196                 drag.target: overlay.itemContainer
0197                 Layout.minimumHeight: Kirigami.Units.gridUnit * 3
0198                 Layout.fillHeight: true
0199                 Layout.fillWidth: true
0200                 cursorShape: containsPress ? Qt.DragMoveCursor : Qt.OpenHandCursor
0201                 hoverEnabled: true
0202                 onPressed: mouse => {
0203                     appletsLayout.releaseSpace(overlay.itemContainer);
0204                 }
0205                 onPositionChanged: mouse => {
0206                     if (!pressed) {
0207                         return;
0208                     }
0209                     appletsLayout.showPlaceHolderForItem(overlay.itemContainer);
0210                     var dragPos = mapToItem(overlay.itemContainer, mouse.x, mouse.y);
0211                     overlay.itemContainer.userDrag(Qt.point(overlay.itemContainer.x, overlay.itemContainer.y), dragPos);
0212                 }
0213                 onReleased: mouse => {
0214                     appletsLayout.hidePlaceHolder();
0215                     appletsLayout.positionItem(overlay.itemContainer);
0216                 }
0217             }
0218 
0219             ActionButton {
0220                 id: closeButton
0221                 icon.name: "edit-delete-remove"
0222                 toolTip: i18n("Remove")
0223                 visible: {
0224                     if (!applet) {
0225                         return false;
0226                     }
0227                     var a = applet.plasmoid.internalAction("remove");
0228                     return a && a.enabled || false;
0229                 }
0230                 // we don't set action, since we want to catch the button click,
0231                 // animate, and then trigger the "remove" action
0232                 // Triggering the action is handled in the overlay.itemContainer, we just
0233                 // Q_EMIT a signal here to avoid the applet-gets-removed-before-we-
0234                 // can-animate it race condition.
0235                 onClicked: {
0236                     removeAnim.restart();
0237                 }
0238                 Component.onCompleted: {
0239                     var a = applet.plasmoid.internalAction("remove");
0240                     if (a) {
0241                         a.enabled = true;
0242                     }
0243                 }
0244             }
0245         }
0246     }
0247 }