/* SPDX-FileCopyrightText: 2013 Marco Martin SPDX-License-Identifier: GPL-2.0-or-later */ // NOTE: Below is taken straight out of Plasma Desktop so that we can // support desktop applets properly, try to keep it in sync: // plasma-desktop/desktoppackage/contents/applet/CompactApplet.qml import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Window 2.15 import org.kde.plasma.core as PlasmaCore import org.kde.ksvg 1.0 as KSvg import org.kde.plasma.plasmoid 2.0 import org.kde.kquickcontrolsaddons 2.0 import org.kde.kirigami 2.20 as Kirigami PlasmaCore.ToolTipArea { id: root objectName: "org.kde.desktop-CompactApplet" anchors.fill: parent mainText: plasmoidItem ? plasmoidItem.toolTipMainText : "" subText: plasmoidItem ? plasmoidItem.toolTipSubText : "" location: Plasmoid.location active: plasmoidItem ? !plasmoidItem.expanded : false textFormat: plasmoidItem ? plasmoidItem.toolTipTextFormat : 0 mainItem: plasmoidItem && plasmoidItem.toolTipItem ? plasmoidItem.toolTipItem : null readonly property bool vertical: location === PlasmaCore.Types.RightEdge || location === PlasmaCore.Types.LeftEdge property Item fullRepresentation property Item compactRepresentation property Item expandedFeedback: expandedItem property PlasmoidItem plasmoidItem onCompactRepresentationChanged: { if (compactRepresentation) { compactRepresentation.anchors.fill = null; compactRepresentation.parent = compactRepresentationParent; compactRepresentation.anchors.fill = compactRepresentationParent; compactRepresentation.visible = true; } root.visible = true; } onFullRepresentationChanged: { if (fullRepresentation) { fullRepresentation.anchors.fill = null; fullRepresentation.parent = appletParent; fullRepresentation.anchors.fill = appletParent; } } FocusScope { id: compactRepresentationParent anchors.fill: parent activeFocusOnTab: true onActiveFocusChanged: { // When the scope gets the active focus, try to focus its first descendant, // if there is on which has activeFocusOnTab if (!activeFocus) { return; } let nextItem = nextItemInFocusChain(); let candidate = nextItem; while (candidate.parent) { if (candidate === compactRepresentationParent) { nextItem.forceActiveFocus(); return; } candidate = candidate.parent; } } objectName: "expandApplet" Accessible.name: root.mainText Accessible.description: i18nd("plasma_shell_org.kde.plasma.desktop", "Open %1", root.subText) Accessible.role: Accessible.Button Accessible.onPressAction: Plasmoid.activated() Keys.onPressed: { switch (event.key) { case Qt.Key_Space: case Qt.Key_Enter: case Qt.Key_Return: case Qt.Key_Select: Plasmoid.activated(); break; } } } KSvg.FrameSvgItem { id: expandedItem z: -100 property var containerMargins: { let item = root; while (item.parent) { item = item.parent; if (item.isAppletContainer) { return item.getMargins; } } return undefined; } anchors { fill: parent property bool returnAllMargins: true // The above makes sure margin is returned even for side margins, that // would be otherwise turned off. bottomMargin: !vertical && containerMargins ? -containerMargins('bottom', returnAllMargins) : 0; topMargin: !vertical && containerMargins ? -containerMargins('top', returnAllMargins) : 0; leftMargin: vertical && containerMargins ? -containerMargins('left', returnAllMargins) : 0; rightMargin: vertical && containerMargins ? -containerMargins('right', returnAllMargins) : 0; } imagePath: "widgets/tabbar" visible: opacity > 0 prefix: { let prefix; switch (Plasmoid.location) { case PlasmaCore.Types.LeftEdge: prefix = "west-active-tab"; break; case PlasmaCore.Types.TopEdge: prefix = "north-active-tab"; break; case PlasmaCore.Types.RightEdge: prefix = "east-active-tab"; break; default: prefix = "south-active-tab"; } if (!hasElementPrefix(prefix)) { prefix = "active-tab"; } return prefix; } opacity: plasmoidItem && plasmoidItem.expanded ? 1 : 0 Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration easing.type: Easing.InOutQuad } } } Timer { id: expandedSync interval: 100 onTriggered: plasmoidItem.expanded = dialog.visible; } Connections { target: Plasmoid.internalAction("configure") function onTriggered() { if (root.plasmoidItem.hideOnWindowDeactivate) { plasmoidItem.expanded = false } } } Connections { target: root.Plasmoid function onContextualActionsAboutToShow() { root.hideImmediately() } } PlasmaCore.AppletPopup { id: dialog objectName: "popupWindow" popupDirection: switch (Plasmoid.location) { case PlasmaCore.Types.TopEdge: return Qt.BottomEdge case PlasmaCore.Types.LeftEdge: return Qt.RightEdge case PlasmaCore.Types.RightEdge: return Qt.LeftEdge default: return Qt.TopEdge } margin: (Plasmoid.containmentDisplayHints & PlasmaCore.Types.ContainmentPrefersFloatingApplets) ? Kirigami.Units.largeSpacing : 0 floating: Plasmoid.location == PlasmaCore.Types.Floating removeBorderStrategy: Plasmoid.location === PlasmaCore.Types.Floating ? PlasmaCore.AppletPopup.AtScreenEdges : PlasmaCore.AppletPopup.AtScreenEdges | PlasmaCore.AppletPopup.AtPanelEdges hideOnWindowDeactivate: root.plasmoidItem && root.plasmoidItem.hideOnWindowDeactivate visible: root.plasmoidItem && root.plasmoidItem.expanded && fullRepresentation visualParent: root.compactRepresentation backgroundHints: (Plasmoid.containmentDisplayHints & PlasmaCore.Types.ContainmentPrefersOpaqueBackground) ? PlasmaCore.AppletPopup.SolidBackground : PlasmaCore.AppletPopup.StandardBackground appletInterface: root.plasmoidItem property var oldStatus: PlasmaCore.Types.UnknownStatus onVisibleChanged: { if (!visible) { expandedSync.restart(); Plasmoid.status = oldStatus; } else { oldStatus = Plasmoid.status; Plasmoid.status = PlasmaCore.Types.RequiresAttentionStatus; // This call currently fails and complains at runtime: // QWindow::setWindowState: QWindow::setWindowState does not accept Qt::WindowActive dialog.requestActivate(); } } //It's a MouseEventListener to get all the events, so the eventfilter will be able to catch them mainItem: MouseEventListener { id: appletParent focus: true Keys.onEscapePressed: { root.plasmoidItem.expanded = false; } Layout.minimumWidth: fullRepresentation ? fullRepresentation.Layout.minimumWidth : 0 Layout.minimumHeight: fullRepresentation ? fullRepresentation.Layout.minimumHeight : 0 Layout.maximumWidth: fullRepresentation ? fullRepresentation.Layout.maximumWidth : Infinity Layout.maximumHeight: fullRepresentation ? fullRepresentation.Layout.maximumHeight : Infinity implicitWidth: { if (root.fullRepresentation !== null) { /****/ if (root.fullRepresentation.Layout.preferredWidth > 0) { return root.fullRepresentation.Layout.preferredWidth; } else if (root.fullRepresentation.implicitWidth > 0) { return root.fullRepresentation.implicitWidth; } } return Kirigami.Units.iconSizes.sizeForLabels * 35; } implicitHeight: { if (root.fullRepresentation !== null) { /****/ if (fullRepresentation.Layout.preferredHeight > 0) { return fullRepresentation.Layout.preferredHeight; } else if (fullRepresentation.implicitHeight > 0) { return fullRepresentation.implicitHeight; } } return Kirigami.Units.iconSizes.sizeForLabels * 25; } onActiveFocusChanged: { if (activeFocus && fullRepresentation) { fullRepresentation.forceActiveFocus() } } // Draws a line between the applet dialog and the panel KSvg.SvgItem { id: separator // Only draw for popups of panel applets, not desktop applets visible: [PlasmaCore.Types.TopEdge, PlasmaCore.Types.LeftEdge, PlasmaCore.Types.RightEdge, PlasmaCore.Types.BottomEdge] .includes(Plasmoid.location) && !dialog.margin anchors { topMargin: -dialog.topPadding leftMargin: -dialog.leftPadding rightMargin: -dialog.rightPadding bottomMargin: -dialog.bottomPadding } z: 999 /* Draw the line on top of the applet */ elementId: (Plasmoid.location === PlasmaCore.Types.TopEdge || Plasmoid.location === PlasmaCore.Types.BottomEdge) ? "horizontal-line" : "vertical-line" imagePath: "widgets/line" states: [ State { when: Plasmoid.location === PlasmaCore.Types.TopEdge AnchorChanges { target: separator anchors { top: separator.parent.top left: separator.parent.left right: separator.parent.right } } PropertyChanges { target: separator height: 1 } }, State { when: Plasmoid.location === PlasmaCore.Types.LeftEdge AnchorChanges { target: separator anchors { left: separator.parent.left top: separator.parent.top bottom: separator.parent.bottom } } PropertyChanges { target: separator width: 1 } }, State { when: Plasmoid.location === PlasmaCore.Types.RightEdge AnchorChanges { target: separator anchors { top: separator.parent.top right: separator.parent.right bottom: separator.parent.bottom } } PropertyChanges { target: separator width: 1 } }, State { when: Plasmoid.location === PlasmaCore.Types.BottomEdge AnchorChanges { target: separator anchors { left: separator.parent.left right: separator.parent.right bottom: separator.parent.bottom } } PropertyChanges { target: separator height: 1 } } ] } LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft LayoutMirroring.childrenInherit: true } } }