75void QQuickPopupPositioner::reposition()
77 auto p = QQuickPopupPrivate::get(popup());
78 QQuickPopupItem *popupItem =
static_cast<QQuickPopupItem *>(m_popup->popupItem());
80 if (p->usePopupWindow()) {
81 repositionPopupWindow();
85 if (!popupItem->isVisible())
93 qCDebug(lcPopupPositioner) <<
"reposition called for" << m_popup;
95 const qreal w = popupItem->width() * m_popupScale;
96 const qreal h = popupItem->height() * m_popupScale;
97 const qreal iw = popupItem->implicitWidth() * m_popupScale;
98 const qreal ih = popupItem->implicitHeight() * m_popupScale;
100 bool widthAdjusted =
false;
101 bool heightAdjusted =
false;
103 const QQuickItem *centerInParent = p->anchors ? p->getAnchors()->centerIn() :
nullptr;
104 const QQuickOverlay *centerInOverlay = qobject_cast<
const QQuickOverlay*>(centerInParent);
105 QRectF rect(!centerInParent ? p->allowHorizontalMove ? p->x : popupItem->x() : 0,
106 !centerInParent ? p->allowVerticalMove ? p->y : popupItem->y() : 0,
107 !p->hasWidth && iw > 0 ? iw : w, !p->hasHeight && ih > 0 ? ih : h);
108 bool relaxEdgeConstraint = p->relaxEdgeConstraint;
115 if (!m_parentItem->window())
118 if (centerInParent) {
119 if (centerInParent != parentItem() && !centerInOverlay) {
120 qmlWarning(m_popup) <<
"Popup can only be centered within its immediate parent or Overlay.overlay";
124 if (centerInOverlay) {
125 rect.moveCenter(QPointF(qRound(centerInOverlay->width() / 2.0), qRound(centerInOverlay->height() / 2.0)));
127 relaxEdgeConstraint =
false;
129 const QPointF parentItemCenter = QPointF(qRound(m_parentItem->width() / 2), qRound(m_parentItem->height() / 2));
130 rect.moveCenter(m_parentItem->mapToItem(popupItem->parentItem(), parentItemCenter));
133 rect.moveTopLeft(m_parentItem->mapToItem(popupItem->parentItem(), rect.topLeft()));
138 QQuickOverlay *overlay = QQuickOverlay::overlay(p->window);
140 qreal boundsWidth = overlay->width();
141 qreal boundsHeight = overlay->height();
145 if (Q_UNLIKELY(boundsWidth <= 0)) {
146 boundsWidth = p->window->width();
147 boundsHeight = p->window->height();
150 const QMarginsF margins = p->getMargins();
151 QRectF bounds(qMax<qreal>(0.0, margins.left()),
152 qMax<qreal>(0.0, margins.top()),
153 boundsWidth - qMax<qreal>(0.0, margins.left()) - qMax<qreal>(0.0, margins.right()),
154 boundsHeight - qMax<qreal>(0.0, margins.top()) - qMax<qreal>(0.0, margins.bottom()));
157 if (p->allowHorizontalFlip && (rect.left() < bounds.left() || rect.right() > bounds.right())) {
158 const QPointF newTopLeft(m_parentItem->width() - p->x - rect.width(), p->y);
159 const QRectF flipped(m_parentItem->mapToItem(popupItem->parentItem(), newTopLeft),
161 if (flipped.intersected(bounds).width() > rect.intersected(bounds).width())
162 rect.moveLeft(flipped.left());
166 if (p->allowVerticalFlip && (rect.top() < bounds.top() || rect.bottom() > bounds.bottom())) {
167 const QPointF newTopLeft(p->x, m_parentItem->height() - p->y - rect.height());
168 const QRectF flipped(m_parentItem->mapToItem(popupItem->parentItem(), newTopLeft),
170 if (flipped.intersected(bounds).height() > rect.intersected(bounds).height())
171 rect.moveTop(flipped.top());
175 if (p->allowVerticalMove) {
176 if (margins.top() >= 0 && rect.top() < bounds.top())
177 rect.moveTop(margins.top());
178 if (margins.bottom() >= 0 && rect.bottom() > bounds.bottom())
179 rect.moveBottom(bounds.bottom());
181 if (p->allowHorizontalMove) {
182 if (margins.left() >= 0 && rect.left() < bounds.left())
183 rect.moveLeft(margins.left());
184 if (margins.right() >= 0 && rect.right() > bounds.right())
185 rect.moveRight(bounds.right());
188 if (iw > 0 && (rect.left() < bounds.left() || rect.right() > bounds.right())) {
191 if (p->allowHorizontalMove && p->allowHorizontalFlip) {
192 if (rect.left() < bounds.left() && bounds.left() + rect.width() <= bounds.right())
193 rect.moveLeft(bounds.left());
194 else if (rect.right() > bounds.right() && bounds.right() - rect.width() >= bounds.left())
195 rect.moveRight(bounds.right());
202 if (p->allowHorizontalResize) {
203 if ((margins.left() >= 0 || !relaxEdgeConstraint)
204 && (rect.left() < bounds.left())) {
205 rect.setLeft(bounds.left());
206 widthAdjusted =
true;
208 if ((margins.right() >= 0 || !relaxEdgeConstraint)
209 && (rect.right() > bounds.right())) {
210 rect.setRight(bounds.right());
211 widthAdjusted =
true;
214 }
else if (iw > 0 && rect.left() >= bounds.left() && rect.right() <= bounds.right()
218 widthAdjusted =
true;
221 if (ih > 0 && (rect.top() < bounds.top() || rect.bottom() > bounds.bottom())) {
224 if (p->allowVerticalMove && p->allowVerticalFlip) {
225 if (rect.top() < bounds.top() && bounds.top() + rect.height() <= bounds.bottom())
226 rect.moveTop(bounds.top());
227 else if (rect.bottom() > bounds.bottom() && bounds.bottom() - rect.height() >= bounds.top())
228 rect.moveBottom(bounds.bottom());
235 if (p->allowVerticalResize) {
236 if ((margins.top() >= 0 || !relaxEdgeConstraint)
237 && (rect.top() < bounds.top())) {
238 rect.setTop(bounds.top());
239 heightAdjusted =
true;
241 if ((margins.bottom() >= 0 || !relaxEdgeConstraint)
242 && (rect.bottom() > bounds.bottom())) {
243 rect.setBottom(bounds.bottom());
244 heightAdjusted =
true;
247 }
else if (ih > 0 && rect.top() >= bounds.top() && rect.bottom() <= bounds.bottom()
251 heightAdjusted =
true;
256 m_positioning =
true;
258 const QPointF windowPos = rect.topLeft();
259 popupItem->setPosition(windowPos);
266 if (m_parentItem && !centerInOverlay)
267 p->setEffectivePosFromWindowPos(m_parentItem->mapFromScene(windowPos));
269 p->setEffectivePosFromWindowPos(windowPos);
271 if (!p->hasWidth && widthAdjusted && rect.width() > 0) {
272 popupItem->setWidth(rect.width() / m_popupScale);
276 QQuickItemPrivate::get(popupItem)->widthValidFlag =
false;
278 if (!p->hasHeight && heightAdjusted && rect.height() > 0) {
279 popupItem->setHeight(rect.height() / m_popupScale);
280 QQuickItemPrivate::get(popupItem)->heightValidFlag =
false;
282 m_positioning =
false;
284 qCDebug(lcPopupPositioner) <<
"- new popupItem geometry:"
285 << popupItem->x() << popupItem->y() << popupItem->width() << popupItem->height();
288void QQuickPopupPositioner::repositionPopupWindow()
290 auto *p = QQuickPopupPrivate::get(popup());
291 QQuickPopupItem *popupItem =
static_cast<QQuickPopupItem *>(m_popup->popupItem());
293 QPointF requestedPos(p->x, p->y);
296 QPointF windowPos = requestedPos - p->windowInsetsTopLeft();
298 if (!p->popupWindow || !p->parentItem) {
302 p->setEffectivePosFromWindowPos(windowPos);
306 const QQuickItem *centerInParent = p->anchors ? p->getAnchors()->centerIn() :
nullptr;
307 const QQuickOverlay *centerInOverlay = qobject_cast<
const QQuickOverlay *>(centerInParent);
308 bool skipFittingStep =
false;
310 if (centerInOverlay) {
311 windowPos = QPoint(qRound((centerInOverlay->width() - p->popupItem->width()) / 2.0),
312 qRound((centerInOverlay->height() - p->popupItem->height()) / 2.0));
313 skipFittingStep =
true;
314 }
else if (centerInParent == p->parentItem) {
315 windowPos = QPoint(qRound((p->parentItem->width() - p->popupItem->width()) / 2.0),
316 qRound((p->parentItem->height() - p->popupItem->height()) / 2.0));
317 skipFittingStep =
true;
318 }
else if (centerInParent)
319 qmlWarning(popup()) <<
"Popup can only be centered within its immediate parent or Overlay.overlay";
321 const QPointF globalCoords = centerInOverlay ? centerInOverlay->mapToGlobal(windowPos.x(), windowPos.y())
322 : p->parentItem->mapToGlobal(windowPos.x(), windowPos.y());
323 QRectF rect = { globalCoords.x(), globalCoords.y(), popupItem->width(), popupItem->height() };
326 static bool isWayland = QGuiApplication::platformName().startsWith(QLatin1String(
"wayland"));
327 if (!skipFittingStep && !isWayland) {
328 const QScreen *screenAtPopupPosition = QGuiApplication::screenAt(globalCoords.toPoint());
329 const QScreen *screen = screenAtPopupPosition ? screenAtPopupPosition : QGuiApplication::primaryScreen();
330 const QRectF bounds = screen->availableGeometry().toRectF();
333 const qreal overlap = popup()->property(
"overlap").toReal();
336 if (
const QQuickPopup *parentPopup = qobject_cast<QQuickPopup *>(popup()->parent())) {
337 padding = parentPopup->leftPadding();
338 scale = parentPopup->scale();
341 if (p->allowHorizontalFlip && (rect.left() < bounds.left() || rect.right() > bounds.right()))
342 rect.moveLeft(rect.left() - requestedPos.x() - rect.width() + overlap * scale - padding);
344 if (p->allowVerticalFlip && (rect.top() < bounds.top() || rect.bottom() > bounds.bottom()))
345 rect.moveTop(rect.top() - requestedPos.y() - rect.height() + overlap * scale);
347 if (rect.left() < bounds.left() || rect.right() > bounds.right()) {
348 if (p->allowHorizontalMove) {
349 if (rect.left() < bounds.left() && bounds.left() + rect.width() <= bounds.right())
350 rect.moveLeft(bounds.left());
351 else if (rect.right() > bounds.right() && bounds.right() - rect.width() >= bounds.left())
352 rect.moveRight(bounds.right());
355 if (rect.top() < bounds.top() || rect.bottom() > bounds.bottom()) {
356 if (p->allowVerticalMove) {
357 if (rect.top() < bounds.top() && bounds.top() + rect.height() <= bounds.bottom())
358 rect.moveTop(bounds.top());
359 else if (rect.bottom() > bounds.bottom() && bounds.bottom() - rect.height() >= bounds.top())
360 rect.moveBottom(bounds.bottom());
365 p->popupWindow->setPosition(rect.x(), rect.y());
366 p->popupItem->setPosition(p->windowInsetsTopLeft());