diff --git a/components/mobileshell/mobileshellplugin.cpp b/components/mobileshell/mobileshellplugin.cpp index 5186290f..2d604e7c 100644 --- a/components/mobileshell/mobileshellplugin.cpp +++ b/components/mobileshell/mobileshellplugin.cpp @@ -74,6 +74,7 @@ void MobileShellPlugin::registerTypes(const char *uri) qmlRegisterType(resolvePath("components/GridView.qml"), uri, 1, 0, "GridView"); qmlRegisterType(resolvePath("components/HapticsEffectLoader.qml"), uri, 1, 0, "HapticsEffectLoader"); qmlRegisterType(resolvePath("components/ListView.qml"), uri, 1, 0, "ListView"); + qmlRegisterType(resolvePath("components/PopupMenu.qml"), uri, 1, 0, "PopupMenu"); qmlRegisterType(resolvePath("components/StartupFeedback.qml"), uri, 1, 0, "StartupFeedback"); qmlRegisterType(resolvePath("components/VelocityCalculator.qml"), uri, 1, 0, "VelocityCalculator"); diff --git a/components/mobileshell/qml/components/PopupMenu.qml b/components/mobileshell/qml/components/PopupMenu.qml new file mode 100644 index 00000000..17120881 --- /dev/null +++ b/components/mobileshell/qml/components/PopupMenu.qml @@ -0,0 +1,97 @@ +import QtQuick +import QtQuick.Layouts + +import org.kde.plasma.components 3.0 as PlasmaComponents +import org.kde.plasma.private.nanoshell as NanoShell +import org.kde.plasma.private.mobileshell as MobileShell +import org.kde.plasma.private.mobileshell.state as MobileShellState + +import org.kde.kirigami as Kirigami + +/* + * A context popup menu closable by tapping outside it. + * Being it a FullScreenOverlay, no event is delivered to underlying components until it's closed. + * + * - property relatedTo: Item to which the popup is related; the popup will spawn either above or below it, depending on its y value. + * If no item is supplied, the popup will spawn at the centre of the screen. + * - property title: The title for the menu. + * - property menuActions: The menu will be composed of these actions. + * - function showOverlay(): Spawns the popup. + */ +NanoShell.FullScreenOverlay { + id: overlay + visible: false + color: "transparent" + + + property point mappedGlobalCoordinates + property Item relatedTo: null + property string title + property list menuActions + + function showOverlay() { + if (!overlay.visible) { + overlay.showMaximized(); + menu.open(); + } + } + + + Item { + id: containerItem + height: menu.implicitHeight + width: menu.implicitWidth + + readonly property point coordinates: { + if (relatedTo) { // Place next to Item + return mapFromGlobal(mappedGlobalCoordinates.x, mappedGlobalCoordinates.y); + } else { // Place at the centre of the screen + return Qt.point((overlay.width - width) / 2, (overlay.height - height) / 2); + } + } + + x: coordinates.x + y: coordinates.y + + transform: Translate { + x: 0 + y: (containerItem.coordinates.y <= overlay.height/2 ? relatedTo.height : -containerItem.height) - MobileShellState.TopPanelControls.panelHeight + } + + PlasmaComponents.Menu { + id: menu + title: overlay.title + closePolicy: PlasmaComponents.Menu.CloseOnReleaseOutside | PlasmaComponents.Menu.CloseOnEscape + + onClosed: overlay.hide() + + Component.onCompleted: { + for (var i = 0; i < menuActions.length; i++) { + appendItem(menuActions[i]); + } + } + + function appendItem(button) { + menu.addItem(menuItem.createObject( + menu, + { + iconName: button.iconName, + text: i18n(button.text), + callback: button.triggered + })); + } + Component { + id: menuItem + + PlasmaComponents.MenuItem { + property string iconName: "" + property var callback: () => {} + + icon.name: iconName + onClicked: callback() + } + } + } + } + +} diff --git a/components/mobileshell/resources.qrc b/components/mobileshell/resources.qrc index fad90ae1..59732d1a 100644 --- a/components/mobileshell/resources.qrc +++ b/components/mobileshell/resources.qrc @@ -28,6 +28,7 @@ qml/components/HapticsEffectWrapper.qml qml/components/ListView.qml qml/components/MarqueeLabel.qml + qml/components/PopupMenu.qml qml/components/StartupFeedback.qml qml/components/util.js qml/components/VelocityCalculator.qml