diff options
| author | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2025-12-15 16:14:22 +0200 |
|---|---|---|
| committer | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2025-12-15 16:14:22 +0200 |
| commit | b58ec3b086518da5aa573f99426235854c23e35f (patch) | |
| tree | 861a9935d8f1cdba2fdca546836a351736dbddbf /src/quick/items | |
| parent | 4826f86e274f1b29bd769e6790824f9e62a40f62 (diff) | |
| parent | 22032227d16c39211e2ebceef97d21f4d89c7c87 (diff) | |
Merge tag 'v6.5.8-lts-lgpl' into 6.56.5
Qt 6.5.8-lts-lgpl release
Diffstat (limited to 'src/quick/items')
| -rw-r--r-- | src/quick/items/qquickflickable.cpp | 4 | ||||
| -rw-r--r-- | src/quick/items/qquickitem.cpp | 60 | ||||
| -rw-r--r-- | src/quick/items/qquickitemview.cpp | 4 | ||||
| -rw-r--r-- | src/quick/items/qquicklistview.cpp | 46 | ||||
| -rw-r--r-- | src/quick/items/qquickmousearea.cpp | 9 | ||||
| -rw-r--r-- | src/quick/items/qquickscreen.cpp | 2 | ||||
| -rw-r--r-- | src/quick/items/qquickwindow.cpp | 29 | ||||
| -rw-r--r-- | src/quick/items/qquickwindow_p.h | 1 |
8 files changed, 113 insertions, 42 deletions
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 77a4bef646..29b2bafa0e 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -1726,7 +1726,9 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) || (yflick() && qAbs(d->accumulatedWheelPixelDelta.y()) > qAbs(d->accumulatedWheelPixelDelta.x() * 2))) { d->drag(currentTimestamp, event->type(), event->position(), d->accumulatedWheelPixelDelta, true, !d->scrollingPhase, true, velocity); - event->accept(); + d->updateBeginningEnd(); + if ((xflick() && !isAtXBeginning() && !isAtXEnd()) || (yflick() && !isAtYBeginning() && !isAtYEnd())) + event->accept(); } else { qCDebug(lcWheel) << "not dragging: accumulated deltas" << d->accumulatedWheelPixelDelta << "moving?" << isMoving() << "can flick horizontally?" << xflick() << "vertically?" << yflick(); diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 1e4af6838d..82587a178a 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2375,6 +2375,20 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item) if (item == item->window()->contentItem()) return true; + const auto tabFocus = QGuiApplication::styleHints()->tabFocusBehavior(); + if (tabFocus == Qt::NoTabFocus) + return false; + if (tabFocus == Qt::TabFocusAllControls) + return true; + + QVariant editable = item->property("editable"); + if (editable.isValid()) + return editable.toBool(); + + QVariant readonly = item->property("readOnly"); + if (readonly.isValid()) + return !readonly.toBool() && item->property("text").isValid(); + #if QT_CONFIG(accessibility) QAccessible::Role role = QQuickItemPrivate::get(item)->effectiveAccessibleRole(); if (role == QAccessible::EditableText || role == QAccessible::Table || role == QAccessible::List) { @@ -2385,14 +2399,6 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item) } #endif - QVariant editable = item->property("editable"); - if (editable.isValid()) - return editable.toBool(); - - QVariant readonly = item->property("readOnly"); - if (readonly.isValid() && !readonly.toBool() && item->property("text").isValid()) - return true; - return false; } @@ -2473,8 +2479,6 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo if (!contentItem) return item; - bool all = QGuiApplication::styleHints()->tabFocusBehavior() == Qt::TabFocusAllControls; - QQuickItem *from = nullptr; bool isTabFence = item->d_func()->isTabFence; if (forward) { @@ -2594,7 +2598,7 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo } } } while (skip || !current->activeFocusOnTab() || !current->isEnabled() || !current->isVisible() - || !(all || QQuickItemPrivate::canAcceptTabFocus(current))); + || !(QQuickItemPrivate::canAcceptTabFocus(current))); return current; } @@ -2666,9 +2670,10 @@ void QQuickItem::setParentItem(QQuickItem *parentItem) while (!scopeItem->isFocusScope() && scopeItem->parentItem()) scopeItem = scopeItem->parentItem(); if (d->window) { - d->deliveryAgentPrivate()-> - clearFocusInScope(scopeItem, scopeFocusedItem, Qt::OtherFocusReason, + if (QQuickDeliveryAgentPrivate *da = d->deliveryAgentPrivate()) { + da->clearFocusInScope(scopeItem, scopeFocusedItem, Qt::OtherFocusReason, QQuickDeliveryAgentPrivate::DontChangeFocusProperty); + } if (scopeFocusedItem != this) QQuickItemPrivate::get(scopeFocusedItem)->updateSubFocusItem(this, true); } else { @@ -2742,9 +2747,10 @@ void QQuickItem::setParentItem(QQuickItem *parentItem) emit scopeFocusedItem->focusChanged(false); } else { if (d->window) { - d->deliveryAgentPrivate()-> - setFocusInScope(scopeItem, scopeFocusedItem, Qt::OtherFocusReason, + if (QQuickDeliveryAgentPrivate *da = d->deliveryAgentPrivate()) { + da->setFocusInScope(scopeItem, scopeFocusedItem, Qt::OtherFocusReason, QQuickDeliveryAgentPrivate::DontChangeFocusProperty); + } } else { QQuickItemPrivate::get(scopeFocusedItem)->updateSubFocusItem(scopeItem, true); } @@ -6499,9 +6505,10 @@ bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible) dirty(Visible); if (parentItem) QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged); - if (window) - if (auto agent = deliveryAgentPrivate(); agent) + if (window) { + if (auto agent = deliveryAgentPrivate()) agent->removeGrabber(q, true, true, true); + } bool childVisibilityChanged = false; for (int ii = 0; ii < childItems.size(); ++ii) @@ -6839,12 +6846,26 @@ void QQuickItem::setSmooth(bool smooth) key events used by Keys or KeyNavigation have precedence over focus chain behavior; ignore the events in other key handlers to allow it to propagate. + + \note {QStyleHints::tabFocusBehavior}{tabFocusBehavior} can further limit focus + to only specific types of controls, such as only text or list controls. This is + the case on macOS, where focus to particular controls may be restricted based on + system settings. + + \sa QStyleHints::tabFocusBehavior, focusPolicy */ /*! \property QQuickItem::activeFocusOnTab This property holds whether the item wants to be in the tab focus chain. By default, this is set to \c false. + + \note {QStyleHints::tabFocusBehavior}{tabFocusBehavior} can further limit focus + to only specific types of controls, such as only text or list controls. This is + the case on macOS, where focus to particular controls may be restricted based on + system settings. + + \sa QStyleHints::tabFocusBehavior, focusPolicy */ bool QQuickItem::activeFocusOnTab() const { @@ -8381,7 +8402,8 @@ void QQuickItem::ungrabTouchPoints() Q_D(QQuickItem); if (!d->window) return; - d->deliveryAgentPrivate()->removeGrabber(this, false, true); + if (QQuickDeliveryAgentPrivate *da = d->deliveryAgentPrivate()) + da->removeGrabber(this, false, true); } /*! @@ -9877,7 +9899,7 @@ QRectF QQuickItem::mapFromItem(const QQuickItem *item, qreal x, qreal y, qreal w //! \internal QPointF QQuickItem::mapToItem(const QQuickItem *item, qreal x, qreal y) -{ return mapToItem(item, QPoint(x, y)); } +{ return mapToItem(item, QPointF(x, y)); } //! \internal QRectF QQuickItem::mapToItem(const QQuickItem *item, const QRectF &rect) const diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 210759585b..2da1f172f1 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -2497,7 +2497,9 @@ bool QQuickItemViewPrivate::releaseItem(FxViewItem *item, QQmlInstanceModel::Reu // One case where this can happen is moving an item out of one ObjectModel and into another. QQuickItemPrivate::get(item->item)->setCulled(true); } - if (!isClearing) + // If deleteLater was called, the item isn't long for this world and so we shouldn't store references to it. + // This can happen when a Repeater is used to populate items in SwipeView's ListView contentItem. + if (!isClearing && !QObjectPrivate::get(item->item)->deleteLaterCalled) unrequestedItems.insert(item->item, model->indexOf(item->item, q)); } else if (flags & QQmlInstanceModel::Destroyed) { item->item->setParentItem(nullptr); diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index 92b66ca5ed..063c48260a 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -2077,7 +2077,7 @@ QQuickItemViewAttached *QQuickListViewPrivate::getAttachedObject(const QObject * The list view itself is a focus scope (see \l{Keyboard Focus in Qt Quick} for more details). Delegates are instantiated as needed and may be destroyed at any time. - As such, state should \e never be stored in a delegate. + As such, \l {Avoid Storing State in Delegates}{state should \e never be stored in a delegate}. Delegates are usually parented to ListView's \l {Flickable::contentItem}{contentItem}, but typically depending on whether it's visible in the view or not, the \e parent can change, and sometimes be \c null. Because of that, binding to @@ -2215,8 +2215,9 @@ QQuickItemViewAttached *QQuickListViewPrivate::getAttachedObject(const QObject * item is reused. This includes \c index and \c row, but also any model roles. - \note Avoid storing any state inside a delegate. If you do, reset it - manually on receiving the \l ListView::reused signal. + \note \l {Avoid Storing State in Delegates}{Avoid storing any state inside + a delegate}. If you do, reset it manually on receiving the + \l ListView::reused signal. If an item has timers or animations, consider pausing them on receiving the \l ListView::pooled signal. That way you avoid using the CPU resources @@ -2248,6 +2249,45 @@ QQuickItemViewAttached *QQuickListViewPrivate::getAttachedObject(const QObject * items, at the expense of additional memory usage. \l{ListView::section}{Sections} have the same effect because they attach and elongate the section label to the first item within the section. + + \section1 Avoid Storing State in Delegates + + ListView's delegates are instantiated as needed and may be destroyed when + out of view. For an illustration of this, run the following example: + + \snippet qml/listview/stateInDelegate.qml ListView + + When an item is clicked, \c channelActivated is set to \c true. However, + because delegates can be \l {Reusing Items}{reused} and destroyed, all + state is lost when the view is moved far enough. When the delegate becomes + visible again, it will have its default, unmodified state (or, in the case + of an item that was reused, old state from a previous item). + + To avoid this, state should be stored in the model: + + \snippet qml/listview/stateInModel.qml ListView + + \section1 Hiding Delegates + + Setting a delegate's \l {Item::}{visible} property to \c false will hide + that item, but the space it occupied in the view will remain. It is + possible to set the item's \l {Item::}{height} to \c 0 (for a \l + {ListView::orientation}{vertical} ListView): + + \snippet qml/listview/hideDelegate.qml ListView + + Note that the hidden state is stored in the model, following the advice of + the \l {Avoid Storing State in Delegates} section. + + However, if \l spacing is non-zero, there will be uneven gaps between + delegates. + + A better option is to filter your model so that items that should not be + visible are not loaded by the view at all. This can be achieved with + \l QSortFilterProxyModel. + + Another option is to \l {Item::enabled}{disable} the delegate instead of + hiding it. */ QQuickListView::QQuickListView(QQuickItem *parent) : QQuickItemView(*(new QQuickListViewPrivate), parent) diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp index 44cbec55b8..b24a733501 100644 --- a/src/quick/items/qquickmousearea.cpp +++ b/src/quick/items/qquickmousearea.cpp @@ -825,6 +825,7 @@ void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event) me.setPosition(d->lastPos); emit mouseYChanged(&me); me.setPosition(d->lastPos); + emit positionChanged(&me); } // A MouseArea should not block hover events @@ -1224,6 +1225,10 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventS { Q_D(QQuickMouseArea); + // Don't allow entering pressed state while invisible + if (p && !d->effectiveVisible) + return false; + #if QT_CONFIG(quick_draganddrop) bool dragged = d->drag && d->drag->active(); #else @@ -1320,6 +1325,10 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventS \endcode The default value is \c Qt.ArrowCursor. + + \note If the \c cursorShape property is set to \c undefined, the \c MouseArea will + not change the existing shape when entering it. + \sa Qt::CursorShape */ diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp index c8405ca9ad..cdcab39773 100644 --- a/src/quick/items/qquickscreen.cpp +++ b/src/quick/items/qquickscreen.cpp @@ -197,8 +197,8 @@ QT_BEGIN_NAMESPACE QQuickScreenInfo::QQuickScreenInfo(QObject *parent, QScreen *wrappedScreen) : QObject(parent) - , m_screen(wrappedScreen) { + setWrappedScreen(wrappedScreen); } QString QQuickScreenInfo::name() const diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 9de90f8d82..d5d5454f22 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -826,13 +826,17 @@ void QQuickWindow::handleApplicationStateChanged(Qt::ApplicationState state) QQmlListProperty<QObject> QQuickWindowPrivate::data() { - return QQmlListProperty<QObject>(q_func(), nullptr, - QQuickWindowPrivate::data_append, - QQuickWindowPrivate::data_count, - QQuickWindowPrivate::data_at, - QQuickWindowPrivate::data_clear, - QQuickWindowPrivate::data_replace, - QQuickWindowPrivate::data_removeLast); + QQmlListProperty<QObject> ret; + + ret.object = q_func(); + ret.append = QQuickWindowPrivate::data_append; + ret.count = QQuickWindowPrivate::data_count; + ret.at = QQuickWindowPrivate::data_at; + ret.clear = QQuickWindowPrivate::data_clear; + // replace is not supported by QQuickItem. Don't synthesize it. + ret.removeLast = QQuickWindowPrivate::data_removeLast; + + return ret; } void QQuickWindowPrivate::dirtyItem(QQuickItem *) @@ -1840,13 +1844,6 @@ void QQuickWindowPrivate::data_clear(QQmlListProperty<QObject> *property) itemProperty.clear(&itemProperty); } -void QQuickWindowPrivate::data_replace(QQmlListProperty<QObject> *property, qsizetype i, QObject *o) -{ - QQuickWindow *win = static_cast<QQuickWindow*>(property->object); - QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data(); - itemProperty.replace(&itemProperty, i, o); -} - void QQuickWindowPrivate::data_removeLast(QQmlListProperty<QObject> *property) { QQuickWindow *win = static_cast<QQuickWindow*>(property->object); @@ -4166,8 +4163,8 @@ void QQuickWindow::setGraphicsConfiguration(const QQuickGraphicsConfiguration &c } /*! - \return the QQuickGraphicsDevice passed to setGraphicsDevice(), or a - default constructed one otherwise + \return the QQuickGraphicsConfiguration passed to + setGraphicsConfiguration(), or a default constructed one otherwise. \since 6.0 diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 558c7d8fc2..6393e4a0cb 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -231,7 +231,6 @@ public: static qsizetype data_count(QQmlListProperty<QObject> *); static QObject *data_at(QQmlListProperty<QObject> *, qsizetype); static void data_clear(QQmlListProperty<QObject> *); - static void data_replace(QQmlListProperty<QObject> *, qsizetype, QObject *); static void data_removeLast(QQmlListProperty<QObject> *); static void rhiCreationFailureMessage(const QString &backendName, |
