diff --git a/src/declarativeimports/plasmacomponents/qmenu.cpp b/src/declarativeimports/plasmacomponents/qmenu.cpp index 8ec146404..926df31c0 100644 --- a/src/declarativeimports/plasmacomponents/qmenu.cpp +++ b/src/declarativeimports/plasmacomponents/qmenu.cpp @@ -22,11 +22,13 @@ #include #include #include +#include #include "plasmacomponentsplugin.h" QMenuProxy::QMenuProxy(QObject *parent) : QObject(parent), - m_status(DialogStatus::Closed) + m_status(DialogStatus::Closed), + m_placement(Plasma::Types::LeftPosedTopAlignedPopup) { m_menu = new QMenu(0); connect(m_menu, &QMenu::triggered, this, &QMenuProxy::itemTriggered); @@ -116,6 +118,20 @@ void QMenuProxy::setTransientParent(QWindow *parent) emit transientParentChanged(); } +Plasma::Types::PopupPlacement QMenuProxy::placement() const +{ + return m_placement; +} + +void QMenuProxy::setPlacement(Plasma::Types::PopupPlacement placement) +{ + if (m_placement != placement) { + m_placement = placement; + + emit placementChanged(); + } +} + int QMenuProxy::minimumWidth() const { return m_menu->minimumWidth(); @@ -222,10 +238,10 @@ void QMenuProxy::itemTriggered(QAction *action) } } -void QMenuProxy::open(int x, int y) +void QMenuProxy::rebuildMenu() { - qDebug() << "opening menu at " << x << y; m_menu->clear(); + foreach (QMenuItem *item, m_items) { if (item->section()) { if (!item->isVisible()) { @@ -240,18 +256,104 @@ void QMenuProxy::open(int x, int y) } } - QQuickItem *parentItem; + m_menu->adjustSize(); +} + +void QMenuProxy::open(int x, int y) +{ + qDebug() << "opening menu at " << x << y; + + QQuickItem *parentItem = nullptr; + if (m_visualParent) { parentItem = qobject_cast(m_visualParent.data()); } else { parentItem = qobject_cast(parent()); } + + if (!parentItem) { + return; + } + + rebuildMenu(); + QPointF pos = parentItem->mapToScene(QPointF(x, y)); + if (parentItem->window() && parentItem->window()->screen()) { pos = parentItem->window()->mapToGlobal(pos.toPoint()); } - m_menu->popup(pos.toPoint()); + openInternal(pos.toPoint()); +} + +Q_INVOKABLE void QMenuProxy::openRelative() +{ + QQuickItem *parentItem = nullptr; + + if (m_visualParent) { + parentItem = qobject_cast(m_visualParent.data()); + } else { + parentItem = qobject_cast(parent()); + } + + if (!parentItem) { + return; + } + + rebuildMenu(); + + QPointF pos; + + using namespace Plasma; + + switch(m_placement) { + case Types::TopPosedLeftAlignedPopup: + case Types::LeftPosedTopAlignedPopup: { + pos = parentItem->mapToScene(QPointF(0, 0)); + break; + } + case Types::TopPosedRightAlignedPopup: + case Types::RightPosedTopAlignedPopup: { + pos = parentItem->mapToScene(QPointF(parentItem->width(), 0)); + break; + } + case Types::LeftPosedBottomAlignedPopup: + case Types::BottomPosedLeftAlignedPopup: { + pos = parentItem->mapToScene(QPointF(0, parentItem->height())); + break; + } + case Types::BottomPosedRightAlignedPopup: + case Types::RightPosedBottomAlignedPopup: { + pos = parentItem->mapToScene(QPointF(parentItem->width(), parentItem->height())); + break; + } + default: + open(); + return; + } + + if (parentItem->window() && parentItem->window()->screen()) { + pos = parentItem->window()->mapToGlobal(pos.toPoint()); + } + + QScreen *screen = parentItem->window()->screen(); + + if (screen) { + if (pos.x() + m_menu->width() > screen->geometry().width()) { + pos.setX(pos.x() - m_menu->width()); + } + + if (pos.y() + m_menu->height() > screen->geometry().height()) { + pos.setY(pos.y() - m_menu->height()); + } + } + + openInternal(pos.toPoint()); +} + +void QMenuProxy::openInternal(QPoint pos) +{ + m_menu->popup(pos); m_status = DialogStatus::Open; emit statusChanged(); } diff --git a/src/declarativeimports/plasmacomponents/qmenu.h b/src/declarativeimports/plasmacomponents/qmenu.h index 34efe67f1..6eb4d8955 100644 --- a/src/declarativeimports/plasmacomponents/qmenu.h +++ b/src/declarativeimports/plasmacomponents/qmenu.h @@ -25,6 +25,7 @@ #include #include "qmenuitem.h" #include "enums.h" +#include "plasma.h" class QDeclarativeItem; @@ -82,6 +83,11 @@ class QMenuProxy : public QObject Q_PROPERTY(QObject *visualParent READ visualParent WRITE setVisualParent NOTIFY visualParentChanged()) Q_PROPERTY(DialogStatus::Status status READ status NOTIFY statusChanged) + /** + * The default placement for the menu. + */ + Q_PROPERTY(Plasma::Types::PopupPlacement placement READ placement WRITE setPlacement NOTIFY placementChanged) + /** * A minimum width for the menu. */ @@ -102,6 +108,9 @@ public: QWindow *transientParent(); void setTransientParent(QWindow *parent); + Plasma::Types::PopupPlacement placement() const; + void setPlacement(Plasma::Types::PopupPlacement placement); + int minimumWidth() const; void setMinimumWidth(int width); @@ -109,7 +118,10 @@ public: * This opens the menu at position x,y on the given visualParent. By default x and y are set to 0 */ Q_INVOKABLE void open(int x = 0, int y = 0); - //Q_INVOKABLE void open(); + /** + * This opens the menu at the specified placement relative to the visualParent. + */ + Q_INVOKABLE void openRelative(); /** * This closes the menu */ @@ -142,6 +154,7 @@ Q_SIGNALS: void statusChanged(); void visualParentChanged(); void transientParentChanged(); + void placementChanged(); void minimumWidthChanged(); void triggered(QMenuItem *item); void triggeredIndex(int index); @@ -150,10 +163,14 @@ private Q_SLOTS: void itemTriggered(QAction *item); private: + void rebuildMenu(); + void openInternal(QPoint pos); + QList m_items; QMenu *m_menu; DialogStatus::Status m_status; QWeakPointer m_visualParent; + Plasma::Types::PopupPlacement m_placement; }; #endif //QMENU_PROXY_H