[Menu] Improve available space correction for openRelative

There was already some kind of detection and adjustment if there is not enough
space for the popup available. Do some more work by placing the popup according
to its PopupPlacement enum. Do this also if the popup breaks the top or left
boundary of the screen.

Also fixes some minor problems:

* TopPosedRightAlignedPopup was the same as RightPosedTopAlignedPopup, but in
  the first case the menu should be on top of parentItem
* LeftPosedTopAlignedPopup was above parentItem and not left of it
* Small documentation error

Reviewers: #plasma, hein

Subscribers: plasma-devel, #frameworks

Tags: #frameworks, #plasma

Differential Revision: https://phabricator.kde.org/D4867
This commit is contained in:
Roman Gilg 2017-03-02 20:58:56 +01:00
parent 2b3e8dfe86
commit daee27f096
2 changed files with 38 additions and 18 deletions

View File

@ -340,29 +340,65 @@ Q_INVOKABLE void QMenuProxy::openRelative()
using namespace Plasma;
auto boundaryCorrection = [&pos, this, parentItem](int hDelta, int vDelta) {
if (!parentItem->window()) {
return;
}
QScreen *screen = parentItem->window()->screen();
if (!screen) {
return;
}
QRect geo = screen->geometry();
pos = parentItem->window()->mapToGlobal(pos.toPoint());
if (pos.x() < geo.x()) {
pos.setX(pos.x() + hDelta);
}
if (pos.y() < geo.y()) {
pos.setY(pos.y() + vDelta);
}
if (geo.x() + geo.width() < pos.x() + this->m_menu->width()) {
pos.setX(pos.x() + hDelta);
}
if (geo.y() + geo.height() < pos.y() + this->m_menu->height()) {
pos.setY(pos.y() + vDelta);
}
};
switch(m_placement) {
case Types::TopPosedLeftAlignedPopup: {
pos = parentItem->mapToScene(QPointF(0, -m_menu->height()));
boundaryCorrection(- m_menu->width() + parentItem->width(), m_menu->height() + parentItem->height());
break;
}
case Types::LeftPosedTopAlignedPopup: {
pos = parentItem->mapToScene(QPointF(0, 0));
pos = parentItem->mapToScene(QPointF(-m_menu->width(), 0));
boundaryCorrection(m_menu->width() + parentItem->width(), - m_menu->height() + parentItem->height());
break;
}
case Types::TopPosedRightAlignedPopup:
pos = parentItem->mapToScene(QPointF(parentItem->width(), -m_menu->height()));
boundaryCorrection(- m_menu->width() + parentItem->width(), m_menu->height()); // in top right corner this will cover the parent item
break;
case Types::RightPosedTopAlignedPopup: {
pos = parentItem->mapToScene(QPointF(parentItem->width(), 0));
boundaryCorrection(- m_menu->width() - parentItem->width(), m_menu->height() + parentItem->height());
break;
}
case Types::LeftPosedBottomAlignedPopup:
pos = parentItem->mapToScene(QPointF(-m_menu->width(), parentItem->height()));
boundaryCorrection(m_menu->width(), - m_menu->height()); // in lower left corner this will cover the parent item
break;
case Types::BottomPosedLeftAlignedPopup: {
pos = parentItem->mapToScene(QPointF(0, parentItem->height()));
boundaryCorrection(- m_menu->width() + parentItem->width(), - m_menu->height() - parentItem->height());
break;
}
case Types::BottomPosedRightAlignedPopup:
case Types::RightPosedBottomAlignedPopup: {
pos = parentItem->mapToScene(QPointF(parentItem->width(), parentItem->height()));
boundaryCorrection(- m_menu->width() + parentItem->width(), - m_menu->height() + parentItem->height());
break;
}
default:
@ -370,22 +406,6 @@ Q_INVOKABLE void QMenuProxy::openRelative()
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().x() + screen->geometry().width())) {
pos.setX(pos.x() - m_menu->width());
}
if (pos.y() + m_menu->height() > (screen->geometry().y() + screen->geometry().height())) {
pos.setY(pos.y() - m_menu->height());
}
}
openInternal(pos.toPoint());
}

View File

@ -173,7 +173,7 @@ public:
TopPosedRightAlignedPopup, /**< Popup positioned on the top, aligned
to the right of the widget */
LeftPosedTopAlignedPopup, /**< Popup positioned on the left, aligned
to the right of the wigdet */
to the top of the wigdet */
LeftPosedBottomAlignedPopup, /**< Popup positioned on the left, aligned
to the bottom of the widget */
BottomPosedLeftAlignedPopup, /**< Popup positioned on the bottom, aligned