diff --git a/applets/notifications/package/contents/ui/ThumbnailStrip.qml b/applets/notifications/package/contents/ui/ThumbnailStrip.qml --- a/applets/notifications/package/contents/ui/ThumbnailStrip.qml +++ b/applets/notifications/package/contents/ui/ThumbnailStrip.qml @@ -111,8 +111,22 @@ preventStealing: true cursorShape: Qt.OpenHandCursor + acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked: notificationItem.openUrl(modelData) + onClicked: { + if (mouse.button === Qt.LeftButton) { + notificationItem.openUrl(modelData); + } + } + + onPressed: { + if (mouse.button === Qt.RightButton) { + // avoid menu button glowing if we didn't actually press it + menuButton.checked = false; + + thumbnailer.showContextMenu(mouse.x, mouse.y, modelData, this); + } + } // cannot drag itself, hence dragging the Pixmap instead drag.target: previewPixmap @@ -193,11 +207,36 @@ } } - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton - onPressed: { - thumbnailer.showContextMenu(mouse.x, mouse.y, modelData, this) + PlasmaComponents.Button { + id: menuButton + anchors { + top: parent.top + right: parent.right + margins: units.smallSpacing + } + width: Math.ceil(units.iconSizes.small + 2 * units.smallSpacing) + height: width + tooltip: i18n("More Options...") + Accessible.name: tooltip + checkable: true + + // -1 tells it to "align bottom left of item (this)" + onClicked: { + checked = Qt.binding(function() { + return thumbnailer.menuVisible; + }); + + thumbnailer.showContextMenu(-1, -1, modelData, this) + } + + PlasmaCore.IconItem { + anchors.fill: parent + anchors.margins: parent.padding + source: "application-menu" + + // From Plasma's ToolButtonStyle: + active: parent.hovered + colorGroup: parent.hovered ? PlasmaCore.Theme.ButtonColorGroup : PlasmaCore.ColorScope.colorGroup } } } diff --git a/applets/notifications/plugin/thumbnailer.h b/applets/notifications/plugin/thumbnailer.h --- a/applets/notifications/plugin/thumbnailer.h +++ b/applets/notifications/plugin/thumbnailer.h @@ -41,6 +41,8 @@ Q_PROPERTY(QString iconName READ iconName NOTIFY iconNameChanged) + Q_PROPERTY(bool menuVisible READ menuVisible NOTIFY menuVisibleChanged) + public: explicit Thumbnailer(QObject *parent = nullptr); ~Thumbnailer() override; @@ -57,12 +59,16 @@ QString iconName() const; + bool menuVisible() const; + Q_INVOKABLE void showContextMenu(int x, int y, const QString &path, QQuickItem *ctx); void classBegin() override; void componentComplete() override; signals: + void menuVisibleChanged(); + void urlChanged(); void sizeChanged(); void pixmapChanged(); @@ -73,6 +79,8 @@ bool m_inited = false; + bool m_menuVisible = false; + QUrl m_url; QSize m_size; diff --git a/applets/notifications/plugin/thumbnailer.cpp b/applets/notifications/plugin/thumbnailer.cpp --- a/applets/notifications/plugin/thumbnailer.cpp +++ b/applets/notifications/plugin/thumbnailer.cpp @@ -107,6 +107,11 @@ return m_iconName; } +bool Thumbnailer::menuVisible() const +{ + return m_menuVisible; +} + void Thumbnailer::showContextMenu(int x, int y, const QString &path, QQuickItem *ctx) { if (!ctx || !ctx->window()) { @@ -123,6 +128,11 @@ QMenu *menu = new QMenu(); menu->setAttribute(Qt::WA_DeleteOnClose, true); + connect(menu, &QMenu::aboutToHide, this, [this] { + m_menuVisible = false; + emit menuVisibleChanged(); + }); + if (KProtocolManager::supportsListing(url)) { QAction *openContainingFolderAction = menu->addAction(QIcon::fromTheme("folder-open"), i18n("Open Containing Folder")); connect(openContainingFolderAction, &QAction::triggered, [url] { @@ -172,9 +182,24 @@ QTimer::singleShot(0, ctx, ungrabMouseHack); //end workaround + QPoint pos; + if (x == -1 && y == -1) { // align "bottom left of ctx" + menu->adjustSize(); + + pos = ctx->mapToGlobal(QPointF(0, ctx->height())).toPoint(); + + if (!qApp->isRightToLeft()) { + pos.rx() += ctx->width(); + pos.rx() -= menu->width(); + } + } else { + pos = ctx->mapToGlobal(QPointF(x, y)).toPoint(); + } - const QPoint pos = ctx->mapToGlobal(QPointF(x, y)).toPoint(); menu->popup(pos); + + m_menuVisible = true; + emit menuVisibleChanged(); } void Thumbnailer::generatePreview()