Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickpopupwindow.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "qquickcombobox_p.h"
6#include "qquickpopup_p.h"
7#include "qquickpopup_p_p.h"
8#include "qquickmenu_p_p.h"
9#include "qquickmenubar_p_p.h"
10#include "qquickpopupitem_p_p.h"
11#include <QtGui/private/qguiapplication_p.h>
12
13#include <QtCore/qloggingcategory.h>
14#include <QtGui/private/qeventpoint_p.h>
15#include <QtQuick/private/qquickitem_p.h>
16#include <QtQuick/private/qquickwindowmodule_p.h>
17#include <QtQuick/private/qquickwindowmodule_p_p.h>
18#include <qpa/qplatformwindow_p.h>
19
21
22Q_STATIC_LOGGING_CATEGORY(lcPopupWindow, "qt.quick.controls.popup.window")
23
25{
26 Q_DECLARE_PUBLIC(QQuickPopupWindow)
27
28public:
29 QPointer<QQuickItem> m_popupItem;
30 QPointer<QQuickPopup> m_popup;
31
32 void forwardEventToParentMenuOrMenuBar(QEvent *event);
33};
34
37{
39
40 d->m_popup = popup;
41 d->m_popupItem = popup->popupItem();
42 setTransientParent(parent);
43
44 connect(d->m_popup, &QQuickPopup::windowChanged, this, &QQuickPopupWindow::windowChanged);
45 connect(d->m_popup, &QQuickPopup::implicitWidthChanged, this, &QQuickPopupWindow::implicitWidthChanged);
46 connect(d->m_popup, &QQuickPopup::implicitHeightChanged, this, &QQuickPopupWindow::implicitHeightChanged);
47 connect(d->m_popup->window(), &QWindow::xChanged, this, &QQuickPopupWindow::parentWindowXChanged);
48 connect(d->m_popup->window(), &QWindow::yChanged, this, &QQuickPopupWindow::parentWindowYChanged);
49
50 setWidth(d->m_popupItem->implicitWidth());
51 setHeight(d->m_popupItem->implicitHeight());
52
53 const auto flags = QQuickPopupPrivate::get(popup)->popupWindowType();
54
55 // For popup windows, we'll need to draw everything, in order to have enough control over the styling.
56 if (flags & Qt::Popup)
58
59 setFlags(flags);
60
61 qCDebug(lcPopupWindow) << "Created popup window with flags: " << flags;
62}
63
65{
67 disconnect(d->m_popup, &QQuickPopup::windowChanged, this, &QQuickPopupWindow::windowChanged);
68 disconnect(d->m_popup, &QQuickPopup::implicitWidthChanged, this, &QQuickPopupWindow::implicitWidthChanged);
69 disconnect(d->m_popup, &QQuickPopup::implicitHeightChanged, this, &QQuickPopupWindow::implicitHeightChanged);
70 disconnect(d->m_popup->window(), &QWindow::xChanged, this, &QQuickPopupWindow::parentWindowXChanged);
71 disconnect(d->m_popup->window(), &QWindow::yChanged, this, &QQuickPopupWindow::parentWindowYChanged);
72}
73
75{
76 Q_D(const QQuickPopupWindow);
77 return d->m_popup;
78}
79
87
89{
90 handlePopupPositionChangeFromWindowSystem(e->pos());
91}
92
94{
97
98 if (!d->m_popupItem)
99 return;
100
101 qCDebug(lcPopupWindow) << "A window system event changed the popup's size to be " << e->size();
102 const QMarginsF windowInsets = QQuickPopupPrivate::get(d->m_popup)->windowInsets();
103 d->m_popupItem->setWidth(e->size().width() - windowInsets.left() - windowInsets.right());
104 d->m_popupItem->setHeight(e->size().height() - windowInsets.top() - windowInsets.bottom());
105}
106
118{
120
121 if (!event->isPointerEvent())
122 return;
123 auto menu = qobject_cast<QQuickMenu *>(q->popup());
124 if (!menu)
125 return;
126
127 auto *pe = static_cast<QPointerEvent *>(event);
128 const QPointF globalPos = pe->points().first().globalPosition();
129
130 // If there is a Menu or a MenuBar under the mouse, resolve its window.
131 QQuickPopupWindow *targetPopupWindow = nullptr;
132 QQuickWindow *targetWindow = nullptr;
133
134 QObject *menuParent = menu;
135 while (menuParent) {
136 if (auto parentMenu = qobject_cast<QQuickMenu *>(menuParent)) {
137 QQuickPopupWindow *popupWindow = QQuickMenuPrivate::get(parentMenu)->popupWindow;
138 auto popup_d = QQuickPopupPrivate::get(popupWindow->popup());
139 QPointF scenePos = popupWindow->contentItem()->mapFromGlobal(globalPos);
140 if (popup_d->contains(scenePos)) {
141 targetPopupWindow = popupWindow;
142 targetWindow = popupWindow;
143 break;
144 }
145 } else if (auto menuBar = qobject_cast<QQuickMenuBar *>(menuParent)) {
146 const QPointF menuBarPos = menuBar->mapFromGlobal(globalPos);
147 if (menuBar->contains(menuBarPos))
148 targetWindow = menuBar->window();
149 break;
150 }
151
152 menuParent = menuParent->parent();
153 }
154
155 if (!targetPopupWindow) {
156 if (pe->isBeginEvent()) {
157 // A QQuickPopupWindow can be bigger than the Popup itself, to make room
158 // for a drop-shadow. Close all popups if the user clicks either on the
159 // shadow or outside the window.
161 return;
162 }
163 }
164
165 if (!targetWindow)
166 return;
167
168 if (pe->isUpdateEvent()){
169 // Forward move events to the target window
170 const auto scenePos = pe->point(0).scenePosition();
171 const auto translatedScenePos = targetWindow->mapFromGlobal(globalPos);
172 QMutableEventPoint::setScenePosition(pe->point(0), translatedScenePos);
173 auto *grabber = pe->exclusiveGrabber(pe->point(0));
174
175 if (grabber) {
176 // Temporarily disable the grabber, to stop the delivery agent inside
177 // targetWindow from forwarding the event to an item outside the menu
178 // or menubar. This is especially important to support a press on e.g
179 // a MenuBarItem, followed by a drag-and-release on top of a MenuItem.
180 pe->setExclusiveGrabber(pe->point(0), nullptr);
181 }
182
183 qCDebug(lcPopupWindow) << "forwarding" << pe << "to popup menu:" << targetWindow;
184 QQuickWindowPrivate::get(targetWindow)->deliveryAgent->event(pe);
185
186 // Restore the event before we return
187 QMutableEventPoint::setScenePosition(pe->point(0), scenePos);
188 if (grabber)
189 pe->setExclusiveGrabber(pe->point(0), grabber);
190 } else if (pe->isEndEvent()) {
191 // To support opening a Menu on press (e.g on a MenuBarItem), followed by
192 // a drag and release on a MenuItem inside the Menu, we ask the Menu to
193 // perform a click on the active MenuItem, if any.
194 if (targetPopupWindow)
195 QQuickPopupPrivate::get(targetPopupWindow->popup())->handleReleaseWithoutGrab(pe->point(0));
196 }
197}
198
200{
202 d->forwardEventToParentMenuOrMenuBar(e);
203
205}
206
207void QQuickPopupWindow::windowChanged(QWindow *window)
208{
209 if (window) {
210 connect(window, &QWindow::xChanged, this, &QQuickPopupWindow::parentWindowXChanged);
211 connect(window, &QWindow::yChanged, this, &QQuickPopupWindow::parentWindowYChanged);
212 }
213}
214
215QPoint QQuickPopupWindow::global2Local(const QPoint &pos) const
216{
217 Q_D(const QQuickPopupWindow);
218 QQuickPopup *popup = d->m_popup;
220 const QPoint scenePos = popup->window()->mapFromGlobal(pos);
221 // Popup's coordinates are relative to the nearest parent item.
222 return popup->parentItem() ? popup->parentItem()->mapFromScene(scenePos).toPoint() : scenePos;
223}
224
225void QQuickPopupWindow::parentWindowXChanged(int newX)
226{
227 const auto popupLocalPos = global2Local({x(), y()});
228 handlePopupPositionChangeFromWindowSystem({newX + popupLocalPos.x(), y()});
229}
230
231void QQuickPopupWindow::parentWindowYChanged(int newY)
232{
233 const auto popupLocalPos = global2Local({x(), y()});
234 handlePopupPositionChangeFromWindowSystem({x(), newY + popupLocalPos.y()});
235}
236
237void QQuickPopupWindow::handlePopupPositionChangeFromWindowSystem(const QPoint &pos)
238{
240 QQuickPopup *popup = d->m_popup;
241 if (!popup)
242 return;
244
245 const auto windowPos = global2Local(pos);
246 qCDebug(lcPopupWindow) << "A window system event changed the popup's position to be " << windowPos;
247 popupPrivate->setEffectivePosFromWindowPos(windowPos);
248}
249
250void QQuickPopupWindow::implicitWidthChanged()
251{
252 Q_D(const QQuickPopupWindow);
253 if (auto popup = d->m_popup)
255}
256
257void QQuickPopupWindow::implicitHeightChanged()
258{
259 Q_D(const QQuickPopupWindow);
260 if (auto popup = d->m_popup)
262}
263
265
\inmodule QtCore
Definition qcoreevent.h:45
static bool closeAllPopups()
Returns true if there are no more open popups.
The QHideEvent class provides an event which is sent after a widget is hidden.
Definition qevent.h:586
\inmodule QtCore
Definition qmargins.h:270
constexpr qreal right() const noexcept
Returns the right margin.
Definition qmargins.h:383
constexpr qreal left() const noexcept
Returns the left margin.
Definition qmargins.h:377
constexpr qreal top() const noexcept
Returns the top margin.
Definition qmargins.h:380
constexpr qreal bottom() const noexcept
Returns the bottom margin.
Definition qmargins.h:386
The QMoveEvent class contains event parameters for move events.
Definition qevent.h:502
const QPoint & pos() const
Returns the new position of the widget.
Definition qevent.h:507
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
Definition qpoint.h:404
\inmodule QtCore\reentrant
Definition qpoint.h:25
A base class for pointer events.
Definition qevent.h:73
QPointF mapFromScene(const QPointF &point) const
Maps the given point in the scene's coordinate system to the equivalent point within this item's coor...
static QQuickMenuPrivate * get(QQuickMenu *menu)
static QQuickPopupPrivate * get(QQuickPopup *popup)
QPointer< QQuickItem > m_popupItem
void forwardEventToParentMenuOrMenuBar(QEvent *event)
QPointer< QQuickPopup > m_popup
void resizeEvent(QResizeEvent *e) override
Override this to handle resize events (ev).
QQuickPopup * popup() const
void hideEvent(QHideEvent *e) override
Override this to handle hide events (ev).
bool event(QEvent *e) override
Override this to handle any event (ev) sent to the window.
void moveEvent(QMoveEvent *e) override
Override this to handle window move events (ev).
QQuickPopupWindow(QQuickPopup *popup, QWindow *parent=nullptr)
void implicitWidthChanged()
void windowChanged(QQuickWindow *window)
qreal implicitWidth
virtual void setVisible(bool visible)
void implicitHeightChanged()
qreal implicitHeight
static QQuickWindowPrivate * get(QQuickWindow *c)
bool event(QEvent *) override
\reimp
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
QQuickItem * contentItem
\qmlattachedproperty Item Window::contentItem
void hideEvent(QHideEvent *) override
\reimp
The QResizeEvent class contains event parameters for resize events.
Definition qevent.h:548
const QSize & size() const
Returns the new size of the widget.
Definition qevent.h:553
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
QWidget * window() const
Returns the window for this widget, i.e.
Definition qwidget.cpp:4329
QPointF mapFromGlobal(const QPointF &) const
Translates the global screen coordinate pos to widget coordinates.
\inmodule QtGui
Definition qwindow.h:63
void setWidth(int arg)
Definition qwindow.cpp:1697
void xChanged(int arg)
Qt::WindowFlags flags
the window flags of the window
Definition qwindow.h:79
void yChanged(int arg)
void setHeight(int arg)
Definition qwindow.cpp:1706
virtual void resizeEvent(QResizeEvent *)
Override this to handle resize events (ev).
Definition qwindow.cpp:2523
constexpr QColor Transparent
Definition qcolor.h:310
Combined button and popup list for selecting options.
@ Popup
Definition qnamespace.h:211
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
GLbitfield flags
struct _cl_event * event
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QObject::connect nullptr
myObject disconnect()
[26]
myFilter setColor(QColor(128, 0, 0))
aWidget window() -> setWindowTitle("New Window Title")
[2]
QMenu menu
[5]
QMenuBar * menuBar
[0]