diff --git a/src/declarativeimports/plasmacomponents/qmenu.cpp b/src/declarativeimports/plasmacomponents/qmenu.cpp index 9f5c5eedf..55e61cdd2 100644 --- a/src/declarativeimports/plasmacomponents/qmenu.cpp +++ b/src/declarativeimports/plasmacomponents/qmenu.cpp @@ -246,6 +246,9 @@ void QMenuProxy::addMenuItem(QMenuItem *item, QMenuItem *before) m_menu->addAction(item->action()); m_items << item; } + connect(item, &QMenuItem::destroyed, this, [this, item]() { + removeMenuItem(item); + }); } void QMenuProxy::addSection(const QString &text) diff --git a/src/declarativeimports/plasmacomponents/qmenuitem.cpp b/src/declarativeimports/plasmacomponents/qmenuitem.cpp index 7885b39ba..cda74ca66 100644 --- a/src/declarativeimports/plasmacomponents/qmenuitem.cpp +++ b/src/declarativeimports/plasmacomponents/qmenuitem.cpp @@ -50,6 +50,7 @@ void QMenuItem::setAction(QAction *a) connect(this, &QQuickItem::visibleChanged, this, &QMenuItem::updateAction); connect(this, &QQuickItem::enabledChanged, this, &QMenuItem::updateAction); + connect(this, &QObject::destroyed, this, &QMenuItem::deleteLater); emit actionChanged(); } diff --git a/src/declarativeimports/plasmaextracomponents/qml/BasicPlasmoidHeading.qml b/src/declarativeimports/plasmaextracomponents/qml/BasicPlasmoidHeading.qml new file mode 100644 index 000000000..e624084f0 --- /dev/null +++ b/src/declarativeimports/plasmaextracomponents/qml/BasicPlasmoidHeading.qml @@ -0,0 +1,130 @@ +/* + SPDX-FileCopyrightText: 2020 Marco Martin + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PC2 +import org.kde.plasma.components 3.0 as PlasmaComponents + + /** + * A standard basic header for plasmoids which has title, a config button and + * a popup menu with all extra plasmoid actions. + * By default, it will be invisible when the plamsoid is in the system tray, as it provides a replacement header with the same features + * + * + * @inherit PlasmoidHeading + */ +PlasmoidHeading { + /** + * extraControls: list + * any extra control and button that may be inserted in the heading + */ + default property alias extraControls: extraControlsLayout.data + + visible: plasmoid.containmentType !== PlasmaCore.Types.CustomEmbeddedContainment + + contentItem: RowLayout { + Heading { + elide: Text.ElideRight + wrapMode: Text.NoWrap + Layout.fillWidth: true + visible: plasmoid.containmentType !== PlasmaCore.Types.CustomEmbeddedContainment + level: 1 + text: plasmoid.title + } + RowLayout { + id: extraControlsLayout + visible: children.length > 0 + Layout.fillHeight: true + } + PlasmaComponents.ToolButton { + id: actionsButton + visible: visibleActions > 0 && plasmoid.containmentType !== PlasmaCore.Types.CustomEmbeddedContainment + checked: configMenu.status !== PC2.DialogStatus.Closed + property int visibleActions: 0 + property QtObject singleAction + + Component.onCompleted: updateVisibleActions() + function updateVisibleActions() { + let newSingleAction = null; + let newVisibleActions = 0; + for (let i in plasmoid.contextualActions) { + let action = plasmoid.contextualActions[i]; + if (action.visible && action !== plasmoid.action("configure")) { + newVisibleActions++; + newSingleAction = action; + action.changed.connect(() => {updateVisibleActions()}); + } + } + if (newVisibleActions > 1) { + newSingleAction = null; + } + visibleActions = newVisibleActions; + singleAction = newSingleAction; + } + Connections { + target: plasmoid + function onContextualActionsChanged() {updateVisibleActions();} + } + icon.name: "application-menu" + checkable: visibleActions > 1 + contentItem.opacity: visibleActions > 1 + // NOTE: it needs an IconItem because QtQuickControls2 buttons cannot load QIcons as their icon + PlasmaCore.IconItem { + parent: actionsButton + anchors.centerIn: parent + active: actionsButton.hovered + implicitWidth: PlasmaCore.Units.iconSizes.smallMedium + implicitHeight: implicitWidth + source: actionsButton.singleAction !== null ? actionsButton.singleAction.icon : "" + visible: actionsButton.singleAction + } + onToggled: { + if (checked) { + configMenu.openRelative(); + } else { + configMenu.close(); + } + } + onClicked: { + if (singleAction) { + singleAction.trigger(); + } + } + PlasmaComponents.ToolTip { + text: actionsButton.singleAction ? actionsButton.singleAction.text : i18n("More actions") + } + PC2.Menu { + id: configMenu + visualParent: actionsButton + placement: PlasmaCore.Types.BottomPosedLeftAlignedPopup + } + + Instantiator { + model: plasmoid.contextualActions + delegate: PC2.MenuItem { + id: menuItem + action: modelData + } + onObjectAdded: { + if (object !== plasmoid.action("configure")) { + configMenu.addMenuItem(object); + } + } + } + } + PlasmaComponents.ToolButton { + icon.name: "configure" + visible: plasmoid && plasmoid.action("configure") && plasmoid.containmentType !== PlasmaCore.Types.CustomEmbeddedContainment + PlasmaComponents.ToolTip { + text: parent.visible ? plasmoid.action("configure").text : "" + } + onClicked: plasmoid.action("configure").trigger(); + } + } +} diff --git a/src/declarativeimports/plasmaextracomponents/qml/qmldir b/src/declarativeimports/plasmaextracomponents/qml/qmldir index e11f532c8..03974c003 100644 --- a/src/declarativeimports/plasmaextracomponents/qml/qmldir +++ b/src/declarativeimports/plasmaextracomponents/qml/qmldir @@ -13,6 +13,7 @@ ScrollArea 2.0 ScrollArea.qml Title 2.0 Title.qml DescriptiveLabel 2.0 DescriptiveLabel.qml PlasmoidHeading 2.0 PlasmoidHeading.qml +BasicPlasmoidHeading 2.0 BasicPlasmoidHeading.qml ActivateAnimation 2.0 animations/ActivateAnimation.qml AppearAnimation 2.0 animations/AppearAnimation.qml diff --git a/src/plasma/plasma.h b/src/plasma/plasma.h index 733fb2bc3..1597634f7 100644 --- a/src/plasma/plasma.h +++ b/src/plasma/plasma.h @@ -95,6 +95,7 @@ public: NoContainmentType = -1, /**< @internal */ DesktopContainment = 0, /**< A desktop containment */ PanelContainment, /**< A desktop panel */ + CustomContainment = 127, /**< A containment that is neither a desktop nor a panel but something application specific */ CustomPanelContainment = 128, /**< A customized desktop panel */ diff --git a/src/scriptengines/qml/plasmoid/appletinterface.cpp b/src/scriptengines/qml/plasmoid/appletinterface.cpp index 7eed339cf..61ae79046 100644 --- a/src/scriptengines/qml/plasmoid/appletinterface.cpp +++ b/src/scriptengines/qml/plasmoid/appletinterface.cpp @@ -114,6 +114,9 @@ AppletInterface::AppletInterface(DeclarativeAppletScript *script, const QVariant connect(applet()->containment(), &Plasma::Containment::screenChanged, this, &AppletInterface::screenGeometryChanged); + connect(applet()->containment(), &Plasma::Containment::containmentTypeChanged, + this, &AppletInterface::containmentTypeChanged); + connect(applet()->containment()->corona(), &Plasma::Corona::screenGeometryChanged, this, [this](int id) { if (id == applet()->containment()->screen()) { emit screenGeometryChanged(); @@ -232,6 +235,15 @@ Plasma::Types::Location AppletInterface::location() const return applet()->location(); } +Plasma::Types::ContainmentType AppletInterface::containmentType() const +{ + if (applet()->containment()) { + return applet()->containment()->containmentType(); + } else { + return Plasma::Types::NoContainmentType; + } +} + QString AppletInterface::currentActivity() const { if (applet()->containment()) { diff --git a/src/scriptengines/qml/plasmoid/appletinterface.h b/src/scriptengines/qml/plasmoid/appletinterface.h index c397e1289..993f2f705 100644 --- a/src/scriptengines/qml/plasmoid/appletinterface.h +++ b/src/scriptengines/qml/plasmoid/appletinterface.h @@ -112,6 +112,12 @@ class AppletInterface : public PlasmaQuick::AppletQuickItem */ Q_PROPERTY(Plasma::Types::FormFactor formFactor READ formFactor NOTIFY formFactorChanged) + /** + * Type of the containment we're in + * @since 5.76 + */ + Q_PROPERTY(Plasma::Types::ContainmentType containmentType READ containmentType NOTIFY containmentTypeChanged) + /** * Location for the plasmoid */ @@ -375,6 +381,8 @@ public: Plasma::Types::Location location() const; + Plasma::Types::ContainmentType containmentType() const; + QString currentActivity() const; QObject *configuration() const; @@ -458,6 +466,7 @@ Q_SIGNALS: void toolTipItemChanged(); void formFactorChanged(); void locationChanged(); + void containmentTypeChanged(); void contextChanged(); void immutabilityChanged(); void statusChanged();