/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Quick Controls module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPLv3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or later as published by the Free ** Software Foundation and appearing in the file LICENSE.GPL included in ** the packaging of this file. Please review the following information to ** ensure the GNU General Public License version 2.0 requirements will be ** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qquickmenupopupwindow_p.h" #include #include #include #include #include #include "qquickmenu_p.h" #include "qquickmenubar_p.h" QT_BEGIN_NAMESPACE QQuickMenuPopupWindow::QQuickMenuPopupWindow(QQuickMenu *menu) : m_itemAt(0), m_logicalParentWindow(0), m_menu(menu) { } void QQuickMenuPopupWindow::setParentItem(QQuickItem *item) { QQuickPopupWindow::setParentItem(item); if (item) { QWindow *parentWindow = item->window(); QWindow *renderWindow = QQuickRenderControl::renderWindowFor(static_cast(parentWindow)); setParentWindow(renderWindow ? renderWindow : parentWindow, item->window()); } } void QQuickMenuPopupWindow::setItemAt(QQuickItem *menuItem) { if (m_itemAt) { disconnect(m_itemAt, SIGNAL(xChanged()), this, SLOT(updatePosition())); disconnect(m_itemAt, SIGNAL(yChanged()), this, SLOT(updatePosition())); } m_itemAt = menuItem; if (menuItem) { m_oldItemPos = menuItem->position().toPoint(); connect(menuItem, SIGNAL(xChanged()), this, SLOT(updatePosition())); connect(menuItem, SIGNAL(yChanged()), this, SLOT(updatePosition())); } } void QQuickMenuPopupWindow::setParentWindow(QWindow *effectiveParentWindow, QQuickWindow *parentWindow) { while (effectiveParentWindow && effectiveParentWindow->parent()) effectiveParentWindow = effectiveParentWindow->parent(); if (transientParent() != effectiveParentWindow) setTransientParent(effectiveParentWindow); m_logicalParentWindow = parentWindow; if (parentWindow) { if (QQuickMenuPopupWindow *pw = qobject_cast(parentWindow)) { connect(pw, SIGNAL(popupDismissed()), this, SLOT(dismissPopup())); connect(pw, SIGNAL(willBeDeletedLater()), this, SLOT(setToBeDeletedLater())); } else { connect(parentWindow, SIGNAL(destroyed()), this, SLOT(deleteLater())); } } } void QQuickMenuPopupWindow::setToBeDeletedLater() { deleteLater(); emit willBeDeletedLater(); } void QQuickMenuPopupWindow::setGeometry(int posx, int posy, int w, int h) { QWindow *pw = transientParent(); if (!pw && parentItem()) pw = parentItem()->window(); if (!pw) pw = this; QRect g = pw->screen()->geometry(); if (posx + w > g.right()) { if (qobject_cast(transientParent())) { // reposition submenu window on the parent menu's left side int submenuOverlap = pw->x() + pw->width() - posx; posx -= pw->width() + w - 2 * submenuOverlap; } else { posx = g.right() - w; } } else { posx = qMax(posx, g.left()); } posy = qBound(g.top(), posy, g.bottom() - h); QQuickWindow::setGeometry(posx, posy, w, h); emit geometryChanged(); } void QQuickMenuPopupWindow::updateSize() { qreal x = m_initialPos.x(); qreal y = m_initialPos.y(); if (qGuiApp->layoutDirection() == Qt::RightToLeft) x -= popupContentItem()->width(); setGeometry(x, y, popupContentItem()->width(), popupContentItem()->height()); } void QQuickMenuPopupWindow::updatePosition() { QPointF newPos = position() + m_oldItemPos - m_itemAt->position(); m_initialPos += m_oldItemPos - m_itemAt->position(); setGeometry(newPos.x(), newPos.y(), width(), height()); } void QQuickMenuPopupWindow::exposeEvent(QExposeEvent *e) { // the popup will reposition at the last moment, so its // initial position must be captured for updateSize(). m_initialPos = position(); if (m_logicalParentWindow && m_logicalParentWindow->parent()) { // This must be a QQuickWindow embedded via createWindowContainer. m_initialPos += m_logicalParentWindow->geometry().topLeft(); } QQuickPopupWindow::exposeEvent(e); } QQuickMenu *QQuickMenuPopupWindow::menu() const { return m_menu; } QQuickMenuBar *QQuickMenuPopupWindow::menuBar() const { QObject *pi = menu()->parentMenuOrMenuBar(); while (pi) { if (QQuickMenuBar *menuBar = qobject_cast(pi)) return menuBar; else if (QQuickMenu *menu = qobject_cast(pi)) pi = menu->parentMenuOrMenuBar(); else return 0; } return 0; } bool QQuickMenuPopupWindow::shouldForwardEventAfterDismiss(QMouseEvent *e) const { // The events that dismissed a popup child of a menu contained in the menubar // are never forwarded if (QQuickMenuBar *mb = menuBar()) { QPoint parentPos = transientParent()->mapFromGlobal(mapToGlobal(e->pos())); if (!mb->isNative() && mb->contentItem()->contains(parentPos)) return false; } #ifdef Q_OS_OSX if (e->button() == Qt::RightButton) return true; #endif #ifdef Q_OS_WIN return true; #endif return false; } QT_END_NAMESPACE