Add a prop and method for aligning the menu against a corner of its visual parent.

REVIEW:127646
This commit is contained in:
Eike Hein 2016-04-14 22:10:24 +09:00
parent 17cea8059e
commit 9bd7e4ce5f
2 changed files with 125 additions and 6 deletions

View File

@ -22,11 +22,13 @@
#include <QDebug>
#include <QQuickWindow>
#include <QQuickItem>
#include <QScreen>
#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<QQuickItem *>(m_visualParent.data());
} else {
parentItem = qobject_cast<QQuickItem *>(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<QQuickItem *>(m_visualParent.data());
} else {
parentItem = qobject_cast<QQuickItem *>(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();
}

View File

@ -25,6 +25,7 @@
#include <QQmlListProperty>
#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<QMenuItem *> m_items;
QMenu *m_menu;
DialogStatus::Status m_status;
QWeakPointer<QObject> m_visualParent;
Plasma::Types::PopupPlacement m_placement;
};
#endif //QMENU_PROXY_H