diff options
Diffstat (limited to 'src/quicktemplates2/qquickpopup.cpp')
-rw-r--r-- | src/quicktemplates2/qquickpopup.cpp | 607 |
1 files changed, 59 insertions, 548 deletions
diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index 4852d08d..f6101973 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -36,14 +36,13 @@ #include "qquickpopup_p.h" #include "qquickpopup_p_p.h" +#include "qquickpopupitem_p_p.h" +#include "qquickpopuppositioner_p_p.h" #include "qquickapplicationwindow_p.h" -#include "qquickshortcutcontext_p_p.h" #include "qquickoverlay_p_p.h" #include "qquickcontrol_p_p.h" #include "qquickdialog_p.h" -#include <QtGui/private/qshortcutmap_p.h> -#include <QtGui/private/qguiapplication_p.h> #include <QtQml/qqmlinfo.h> #include <QtQuick/qquickitem.h> #include <QtQuick/private/qquicktransition_p.h> @@ -188,56 +187,49 @@ QT_BEGIN_NAMESPACE \sa opened */ -static const QQuickItemPrivate::ChangeTypes AncestorChangeTypes = QQuickItemPrivate::Geometry - | QQuickItemPrivate::Parent - | QQuickItemPrivate::Children; - -static const QQuickItemPrivate::ChangeTypes ItemChangeTypes = QQuickItemPrivate::Geometry - | QQuickItemPrivate::Parent; - QQuickPopupPrivate::QQuickPopupPrivate() - : QObjectPrivate() - , focus(false) - , modal(false) - , dim(false) - , hasDim(false) - , visible(false) - , complete(false) - , positioning(false) - , hasWidth(false) - , hasHeight(false) - , hasTopMargin(false) - , hasLeftMargin(false) - , hasRightMargin(false) - , hasBottomMargin(false) - , allowVerticalFlip(false) - , allowHorizontalFlip(false) - , allowVerticalMove(true) - , allowHorizontalMove(true) - , allowVerticalResize(true) - , allowHorizontalResize(true) - , hadActiveFocusBeforeExitTransition(false) - , x(0) - , y(0) - , effectiveX(0) - , effectiveY(0) - , margins(-1) - , topMargin(0) - , leftMargin(0) - , rightMargin(0) - , bottomMargin(0) - , contentWidth(0) - , contentHeight(0) - , transitionState(QQuickPopupPrivate::NoTransition) - , closePolicy(QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutside) - , parentItem(nullptr) - , dimmer(nullptr) - , window(nullptr) - , enter(nullptr) - , exit(nullptr) - , popupItem(nullptr) - , positioner(this) - , transitionManager(this) + : focus(false), + modal(false), + dim(false), + hasDim(false), + visible(false), + complete(false), + positioning(false), + hasWidth(false), + hasHeight(false), + hasTopMargin(false), + hasLeftMargin(false), + hasRightMargin(false), + hasBottomMargin(false), + allowVerticalFlip(false), + allowHorizontalFlip(false), + allowVerticalMove(true), + allowHorizontalMove(true), + allowVerticalResize(true), + allowHorizontalResize(true), + hadActiveFocusBeforeExitTransition(false), + interactive(true), + x(0), + y(0), + effectiveX(0), + effectiveY(0), + margins(-1), + topMargin(0), + leftMargin(0), + rightMargin(0), + bottomMargin(0), + contentWidth(0), + contentHeight(0), + transitionState(QQuickPopupPrivate::NoTransition), + closePolicy(QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutside), + parentItem(nullptr), + dimmer(nullptr), + window(nullptr), + enter(nullptr), + exit(nullptr), + popupItem(nullptr), + positioner(nullptr), + transitionManager(this) { } @@ -251,26 +243,30 @@ void QQuickPopupPrivate::init() popupItem = new QQuickPopupItem(q); q->setParentItem(qobject_cast<QQuickItem *>(parent)); QObject::connect(popupItem, &QQuickControl::paddingChanged, q, &QQuickPopup::paddingChanged); + positioner = new QQuickPopupPositioner(q); } -static void closeOrReject(QQuickPopup *popup) +void QQuickPopupPrivate::closeOrReject() { - if (QQuickDialog *dialog = qobject_cast<QQuickDialog*>(popup)) + Q_Q(QQuickPopup); + if (QQuickDialog *dialog = qobject_cast<QQuickDialog*>(q)) dialog->reject(); else - popup->close(); + q->close(); } bool QQuickPopupPrivate::tryClose(QQuickItem *item, QMouseEvent *event) { - Q_Q(QQuickPopup); + if (!interactive) + return false; + const bool isPress = event->type() == QEvent::MouseButtonPress; const bool onOutside = closePolicy.testFlag(isPress ? QQuickPopup::CloseOnPressOutside : QQuickPopup::CloseOnReleaseOutside); const bool onOutsideParent = closePolicy.testFlag(isPress ? QQuickPopup::CloseOnPressOutsideParent : QQuickPopup::CloseOnReleaseOutsideParent); if (onOutside || onOutsideParent) { if (!popupItem->contains(item->mapToItem(popupItem, event->pos()))) { if (!onOutsideParent || !parentItem || !parentItem->contains(item->mapToItem(parentItem, event->pos()))) { - closeOrReject(q); + closeOrReject(); return true; } } @@ -282,7 +278,7 @@ bool QQuickPopupPrivate::prepareEnterTransition() { Q_Q(QQuickPopup); if (!window) { - qmlInfo(q) << "cannot find any window to open popup in."; + qmlWarning(q) << "cannot find any window to open popup in."; return false; } @@ -295,7 +291,7 @@ bool QQuickPopupPrivate::prepareEnterTransition() visible = true; transitionState = EnterTransition; popupItem->setVisible(true); - positioner.setParentItem(parentItem); + positioner->setParentItem(parentItem); emit q->visibleChanged(); } return true; @@ -332,7 +328,7 @@ void QQuickPopupPrivate::finalizeEnterTransition() void QQuickPopupPrivate::finalizeExitTransition() { Q_Q(QQuickPopup); - positioner.setParentItem(nullptr); + positioner->setParentItem(nullptr); popupItem->setParentItem(nullptr); popupItem->setVisible(false); @@ -433,314 +429,6 @@ void QQuickPopupPrivate::setWindow(QQuickWindow *newWindow) emit q->windowChanged(newWindow); } -class QQuickPopupItemPrivate : public QQuickControlPrivate -{ - Q_DECLARE_PUBLIC(QQuickPopupItem) - -public: - QQuickPopupItemPrivate(QQuickPopup *popup); - - void implicitWidthChanged() override; - void implicitHeightChanged() override; - - void resolveFont() override; - - QQuickItem *getContentItem() override; - - int backId; - int escapeId; - QQuickPopup *popup; -}; - -QQuickPopupItemPrivate::QQuickPopupItemPrivate(QQuickPopup *popup) - : backId(0), - escapeId(0), - popup(popup) -{ - isTabFence = true; -} - -void QQuickPopupItemPrivate::implicitWidthChanged() -{ - QQuickControlPrivate::implicitWidthChanged(); - emit popup->implicitWidthChanged(); -} - -void QQuickPopupItemPrivate::implicitHeightChanged() -{ - QQuickControlPrivate::implicitHeightChanged(); - emit popup->implicitHeightChanged(); -} - -void QQuickPopupItemPrivate::resolveFont() -{ - if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(popup->window())) - inheritFont(window->font()); -} - -QQuickItem *QQuickPopupItemPrivate::getContentItem() -{ - Q_Q(QQuickPopupItem); - if (!contentItem) - contentItem = new QQuickItem(q); - return contentItem; -} - -QQuickPopupItem::QQuickPopupItem(QQuickPopup *popup) : - QQuickControl(*(new QQuickPopupItemPrivate(popup)), nullptr) -{ - setParent(popup); - setVisible(false); - setFlag(ItemIsFocusScope); - setAcceptedMouseButtons(Qt::AllButtons); - - // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8 - setHoverEnabled(true); - // setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects()); - // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, this, &QQuickItem::setAcceptHoverEvents); -} - -void QQuickPopupItem::updatePolish() -{ - Q_D(QQuickPopupItem); - return QQuickPopupPrivate::get(d->popup)->reposition(); -} - -void QQuickPopupItem::grabShortcut() -{ -#ifndef QT_NO_SHORTCUT - Q_D(QQuickPopupItem); - QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance(); - if (!d->backId) - d->backId = pApp->shortcutMap.addShortcut(this, Qt::Key_Back, Qt::WindowShortcut, QQuickShortcutContext::matcher); - if (!d->escapeId) - d->escapeId = pApp->shortcutMap.addShortcut(this, Qt::Key_Escape, Qt::WindowShortcut, QQuickShortcutContext::matcher); -#endif // QT_NO_SHORTCUT -} - -void QQuickPopupItem::ungrabShortcut() -{ -#ifndef QT_NO_SHORTCUT - Q_D(QQuickPopupItem); - QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance(); - if (d->backId) { - pApp->shortcutMap.removeShortcut(d->backId, this); - d->backId = 0; - } - if (d->escapeId) { - pApp->shortcutMap.removeShortcut(d->escapeId, this); - d->escapeId = 0; - } -#endif // QT_NO_SHORTCUT -} - -bool QQuickPopupItem::event(QEvent *event) -{ - Q_D(QQuickPopupItem); - if (event->type() == QEvent::Shortcut) { - QShortcutEvent *se = static_cast<QShortcutEvent *>(event); - if (se->shortcutId() == d->escapeId || se->shortcutId() == d->backId) { - closeOrReject(d->popup); - return true; - } - } - return QQuickItem::event(event); -} - -bool QQuickPopupItem::childMouseEventFilter(QQuickItem *child, QEvent *event) -{ - Q_D(QQuickPopupItem); - return d->popup->childMouseEventFilter(child, event); -} - -void QQuickPopupItem::focusInEvent(QFocusEvent *event) -{ - Q_D(QQuickPopupItem); - d->popup->focusInEvent(event); -} - -void QQuickPopupItem::focusOutEvent(QFocusEvent *event) -{ - Q_D(QQuickPopupItem); - d->popup->focusOutEvent(event); -} - -void QQuickPopupItem::keyPressEvent(QKeyEvent *event) -{ - Q_D(QQuickPopupItem); - d->popup->keyPressEvent(event); -} - -void QQuickPopupItem::keyReleaseEvent(QKeyEvent *event) -{ - Q_D(QQuickPopupItem); - d->popup->keyReleaseEvent(event); -} - -void QQuickPopupItem::mousePressEvent(QMouseEvent *event) -{ - Q_D(QQuickPopupItem); - d->popup->mousePressEvent(event); -} - -void QQuickPopupItem::mouseMoveEvent(QMouseEvent *event) -{ - Q_D(QQuickPopupItem); - d->popup->mouseMoveEvent(event); -} - -void QQuickPopupItem::mouseReleaseEvent(QMouseEvent *event) -{ - Q_D(QQuickPopupItem); - d->popup->mouseReleaseEvent(event); -} - -void QQuickPopupItem::mouseDoubleClickEvent(QMouseEvent *event) -{ - Q_D(QQuickPopupItem); - d->popup->mouseDoubleClickEvent(event); -} - -void QQuickPopupItem::mouseUngrabEvent() -{ - Q_D(QQuickPopupItem); - d->popup->mouseUngrabEvent(); -} - -void QQuickPopupItem::wheelEvent(QWheelEvent *event) -{ - Q_D(QQuickPopupItem); - d->popup->wheelEvent(event); -} - -void QQuickPopupItem::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) -{ - Q_D(QQuickPopupItem); - QQuickControl::contentItemChange(newItem, oldItem); - d->popup->contentItemChange(newItem, oldItem); -} - -void QQuickPopupItem::fontChange(const QFont &newFont, const QFont &oldFont) -{ - Q_D(QQuickPopupItem); - QQuickControl::fontChange(newFont, oldFont); - d->popup->fontChange(newFont, oldFont); -} - -void QQuickPopupItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - Q_D(QQuickPopupItem); - QQuickControl::geometryChanged(newGeometry, oldGeometry); - d->popup->geometryChanged(newGeometry, oldGeometry); -} - -void QQuickPopupItem::localeChange(const QLocale &newLocale, const QLocale &oldLocale) -{ - Q_D(QQuickPopupItem); - QQuickControl::localeChange(newLocale, oldLocale); - d->popup->localeChange(newLocale, oldLocale); -} - -void QQuickPopupItem::itemChange(ItemChange change, const ItemChangeData &data) -{ - Q_D(QQuickPopupItem); - QQuickControl::itemChange(change, data); - d->popup->itemChange(change, data); -} - -void QQuickPopupItem::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) -{ - Q_D(QQuickPopupItem); - QQuickControl::paddingChange(newPadding, oldPadding); - d->popup->paddingChange(newPadding, oldPadding); -} - -void QQuickPopupItem::spacingChange(qreal newSpacing, qreal oldSpacing) -{ - Q_D(QQuickPopupItem); - QQuickControl::spacingChange(newSpacing, oldSpacing); - d->popup->spacingChange(newSpacing, oldSpacing); -} - -QFont QQuickPopupItem::defaultFont() const -{ - Q_D(const QQuickPopupItem); - return d->popup->defaultFont(); -} - -#ifndef QT_NO_ACCESSIBILITY -QAccessible::Role QQuickPopupItem::accessibleRole() const -{ - Q_D(const QQuickPopupItem); - return d->popup->accessibleRole(); -} - -void QQuickPopupItem::accessibilityActiveChanged(bool active) -{ - Q_D(const QQuickPopupItem); - QQuickControl::accessibilityActiveChanged(active); - d->popup->accessibilityActiveChanged(active); -} -#endif // QT_NO_ACCESSIBILITY - -QQuickPopupPositioner::QQuickPopupPositioner(QQuickPopupPrivate *popup) : - m_parentItem(nullptr), - m_popup(popup) -{ -} - -QQuickPopupPositioner::~QQuickPopupPositioner() -{ - if (m_parentItem) { - QQuickItemPrivate::get(m_parentItem)->removeItemChangeListener(this, ItemChangeTypes); - removeAncestorListeners(m_parentItem->parentItem()); - } -} - -QQuickItem *QQuickPopupPositioner::parentItem() const -{ - return m_parentItem; -} - -void QQuickPopupPositioner::setParentItem(QQuickItem *parent) -{ - if (m_parentItem == parent) - return; - - if (m_parentItem) { - QQuickItemPrivate::get(m_parentItem)->removeItemChangeListener(this, ItemChangeTypes); - removeAncestorListeners(m_parentItem->parentItem()); - } - - m_parentItem = parent; - - if (!parent) - return; - - QQuickItemPrivate::get(parent)->addItemChangeListener(this, ItemChangeTypes); - addAncestorListeners(parent->parentItem()); - - if (m_popup->popupItem->isVisible()) - m_popup->reposition(); -} - -void QQuickPopupPositioner::itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) -{ - if (m_parentItem && m_popup->popupItem->isVisible()) - m_popup->reposition(); -} - -void QQuickPopupPositioner::itemParentChanged(QQuickItem *, QQuickItem *parent) -{ - addAncestorListeners(parent); -} - -void QQuickPopupPositioner::itemChildRemoved(QQuickItem *item, QQuickItem *child) -{ - if (isAncestor(child)) - removeAncestorListeners(item); -} - void QQuickPopupPrivate::itemDestroyed(QQuickItem *item) { Q_Q(QQuickPopup); @@ -750,143 +438,7 @@ void QQuickPopupPrivate::itemDestroyed(QQuickItem *item) void QQuickPopupPrivate::reposition() { - Q_Q(QQuickPopup); - if (!popupItem->isVisible()) - return; - - if (positioning) { - popupItem->polish(); - return; - } - - const qreal w = popupItem->width(); - const qreal h = popupItem->height(); - const qreal iw = popupItem->implicitWidth(); - const qreal ih = popupItem->implicitHeight(); - - bool widthAdjusted = false; - bool heightAdjusted = false; - - QRectF rect(allowHorizontalMove ? x : popupItem->x(), - allowVerticalMove ? y : popupItem->y(), - !hasWidth && iw > 0 ? iw : w, - !hasHeight && ih > 0 ? ih : h); - if (parentItem) { - rect = parentItem->mapRectToScene(rect); - - if (window) { - const QMarginsF margins = getMargins(); - const QRectF bounds(qMax<qreal>(0.0, margins.left()), - qMax<qreal>(0.0, margins.top()), - window->width() - qMax<qreal>(0.0, margins.left()) - qMax<qreal>(0.0, margins.right()), - window->height() - qMax<qreal>(0.0, margins.top()) - qMax<qreal>(0.0, margins.bottom())); - - // if the popup doesn't fit horizontally inside the window, try flipping it around (left <-> right) - if (allowHorizontalFlip && (rect.left() < bounds.left() || rect.right() > bounds.right())) { - const QRectF flipped = parentItem->mapRectToScene(QRectF(parentItem->width() - x - rect.width(), y, rect.width(), rect.height())); - if (flipped.intersected(bounds).width() > rect.intersected(bounds).width()) - rect.moveLeft(flipped.left()); - } - - // if the popup doesn't fit vertically inside the window, try flipping it around (above <-> below) - if (allowVerticalFlip && (rect.top() < bounds.top() || rect.bottom() > bounds.bottom())) { - const QRectF flipped = parentItem->mapRectToScene(QRectF(x, parentItem->height() - y - rect.height(), rect.width(), rect.height())); - if (flipped.intersected(bounds).height() > rect.intersected(bounds).height()) - rect.moveTop(flipped.top()); - } - - // push inside the margins if specified - if (allowVerticalMove) { - if (margins.top() >= 0 && rect.top() < bounds.top()) - rect.moveTop(margins.top()); - if (margins.bottom() >= 0 && rect.bottom() > bounds.bottom()) - rect.moveBottom(bounds.bottom()); - } - if (allowHorizontalMove) { - if (margins.left() >= 0 && rect.left() < bounds.left()) - rect.moveLeft(margins.left()); - if (margins.right() >= 0 && rect.right() > bounds.right()) - rect.moveRight(bounds.right()); - } - - if (iw > 0 && (rect.left() < bounds.left() || rect.right() > bounds.right())) { - // neither the flipped or pushed geometry fits inside the window, choose - // whichever side (left vs. right) fits larger part of the popup - if (allowHorizontalMove && allowHorizontalFlip) { - if (rect.left() < bounds.left() && bounds.left() + rect.width() <= bounds.right()) - rect.moveLeft(bounds.left()); - else if (rect.right() > bounds.right() && bounds.right() - rect.width() >= bounds.left()) - rect.moveRight(bounds.right()); - } - - // as a last resort, adjust the width to fit the window - if (allowHorizontalResize) { - if (rect.left() < bounds.left()) { - rect.setLeft(bounds.left()); - widthAdjusted = true; - } - if (rect.right() > bounds.right()) { - rect.setRight(bounds.right()); - widthAdjusted = true; - } - } - } else if (iw > 0 && rect.left() >= bounds.left() && rect.right() <= bounds.right() - && iw != w) { - // restore original width - rect.setWidth(iw); - widthAdjusted = true; - } - - if (ih > 0 && (rect.top() < bounds.top() || rect.bottom() > bounds.bottom())) { - // neither the flipped or pushed geometry fits inside the window, choose - // whichever side (above vs. below) fits larger part of the popup - if (allowVerticalMove && allowVerticalFlip) { - if (rect.top() < bounds.top() && bounds.top() + rect.height() <= bounds.bottom()) - rect.moveTop(bounds.top()); - else if (rect.bottom() > bounds.bottom() && bounds.bottom() - rect.height() >= bounds.top()) - rect.moveBottom(bounds.bottom()); - } - - // as a last resort, adjust the height to fit the window - if (allowVerticalResize) { - if (rect.top() < bounds.top()) { - rect.setTop(bounds.top()); - heightAdjusted = true; - } - if (rect.bottom() > bounds.bottom()) { - rect.setBottom(bounds.bottom()); - heightAdjusted = true; - } - } - } else if (ih > 0 && rect.top() >= bounds.top() && rect.bottom() <= bounds.bottom() - && ih != h) { - // restore original height - rect.setHeight(ih); - heightAdjusted = true; - } - } - } - - positioning = true; - - popupItem->setPosition(rect.topLeft()); - - const QPointF effectivePos = parentItem ? parentItem->mapFromScene(rect.topLeft()) : rect.topLeft(); - if (!qFuzzyCompare(effectiveX, effectivePos.x())) { - effectiveX = effectivePos.x(); - emit q->xChanged(); - } - if (!qFuzzyCompare(effectiveY, effectivePos.y())) { - effectiveY = effectivePos.y(); - emit q->yChanged(); - } - - if (!hasWidth && widthAdjusted && rect.width() > 0) - popupItem->setWidth(rect.width()); - if (!hasHeight && heightAdjusted && rect.height() > 0) - popupItem->setHeight(rect.height()); - - positioning = false; + positioner->reposition(); } void QQuickPopupPrivate::resizeOverlay() @@ -899,45 +451,6 @@ void QQuickPopupPrivate::resizeOverlay() dimmer->setSize(QSizeF(w, h)); } -void QQuickPopupPositioner::removeAncestorListeners(QQuickItem *item) -{ - if (item == m_parentItem) - return; - - QQuickItem *p = item; - while (p) { - QQuickItemPrivate::get(p)->removeItemChangeListener(this, AncestorChangeTypes); - p = p->parentItem(); - } -} - -void QQuickPopupPositioner::addAncestorListeners(QQuickItem *item) -{ - if (item == m_parentItem) - return; - - QQuickItem *p = item; - while (p) { - QQuickItemPrivate::get(p)->addItemChangeListener(this, AncestorChangeTypes); - p = p->parentItem(); - } -} - -// TODO: use QQuickItem::isAncestorOf() in dev/5.7 -bool QQuickPopupPositioner::isAncestor(QQuickItem *item) const -{ - if (!m_parentItem) - return false; - - QQuickItem *parent = m_parentItem; - while (parent) { - if (parent == item) - return true; - parent = parent->parentItem(); - } - return false; -} - QQuickPopupTransitionManager::QQuickPopupTransitionManager(QQuickPopupPrivate *popup) : QQuickTransitionManager(), popup(popup) { @@ -1719,8 +1232,8 @@ void QQuickPopup::setParentItem(QQuickItem *parent) QQuickItemPrivate::get(d->parentItem)->removeItemChangeListener(d, QQuickItemPrivate::Destroyed); } d->parentItem = parent; - if (d->positioner.parentItem()) - d->positioner.setParentItem(parent); + if (d->positioner->parentItem()) + d->positioner->setParentItem(parent); if (parent) { QObjectPrivate::connect(parent, &QQuickItem::windowChanged, d, &QQuickPopupPrivate::setWindow); QQuickItemPrivate::get(d->parentItem)->addItemChangeListener(d, QQuickItemPrivate::Destroyed); @@ -2460,5 +1973,3 @@ bool QQuickPopup::setAccessibleProperty(const char *propertyName, const QVariant } QT_END_NAMESPACE - -#include "moc_qquickpopup_p.cpp" |