diff options
Diffstat (limited to 'src/quick/items/qquickitem.cpp')
-rw-r--r-- | src/quick/items/qquickitem.cpp | 329 |
1 files changed, 279 insertions, 50 deletions
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index fbea3a0ee1..224decefec 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -72,14 +72,14 @@ #endif #include <algorithm> -#include <float.h> +#include <limits> // XXX todo Check that elements that create items handle memory correctly after visual ownership change QT_BEGIN_NAMESPACE #ifndef QT_NO_DEBUG -static bool qsg_leak_check = !qgetenv("QML_LEAK_CHECK").isEmpty(); +static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK"); #endif void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1) @@ -217,8 +217,8 @@ bool QQuickContents::calcHeight(QQuickItem *changed) m_y = top; m_height = bottom - top; } else { - qreal top = FLT_MAX; - qreal bottom = 0; + qreal top = std::numeric_limits<qreal>::max(); + qreal bottom = -std::numeric_limits<qreal>::max(); QList<QQuickItem *> children = m_item->childItems(); for (int i = 0; i < children.count(); ++i) { QQuickItem *child = children.at(i); @@ -252,8 +252,8 @@ bool QQuickContents::calcWidth(QQuickItem *changed) m_x = left; m_width = right - left; } else { - qreal left = FLT_MAX; - qreal right = 0; + qreal left = std::numeric_limits<qreal>::max(); + qreal right = -std::numeric_limits<qreal>::max(); QList<QQuickItem *> children = m_item->childItems(); for (int i = 0; i < children.count(); ++i) { QQuickItem *child = children.at(i); @@ -622,7 +622,7 @@ void QQuickKeyNavigationAttached::keyPressed(QKeyEvent *event, bool post) mirror = QQuickItemPrivate::get(parentItem)->effectiveLayoutMirror; QQuickItem* leftItem = mirror ? d->right : d->left; if (leftItem) { - setFocusNavigation(leftItem, mirror ? "right" : "left"); + setFocusNavigation(leftItem, mirror ? "right" : "left", mirror ? Qt::TabFocusReason : Qt::BacktabFocusReason); event->accept(); } break; @@ -632,20 +632,20 @@ void QQuickKeyNavigationAttached::keyPressed(QKeyEvent *event, bool post) mirror = QQuickItemPrivate::get(parentItem)->effectiveLayoutMirror; QQuickItem* rightItem = mirror ? d->left : d->right; if (rightItem) { - setFocusNavigation(rightItem, mirror ? "left" : "right"); + setFocusNavigation(rightItem, mirror ? "left" : "right", mirror ? Qt::BacktabFocusReason : Qt::TabFocusReason); event->accept(); } break; } case Qt::Key_Up: if (d->up) { - setFocusNavigation(d->up, "up"); + setFocusNavigation(d->up, "up", Qt::BacktabFocusReason); event->accept(); } break; case Qt::Key_Down: if (d->down) { - setFocusNavigation(d->down, "down"); + setFocusNavigation(d->down, "down", Qt::TabFocusReason); event->accept(); } break; @@ -1306,8 +1306,8 @@ void QQuickKeysAttached::setPriority(Priority order) void QQuickKeysAttached::componentComplete() { - Q_D(QQuickKeysAttached); #ifndef QT_NO_IM + Q_D(QQuickKeysAttached); if (d->item) { for (int ii = 0; ii < d->targets.count(); ++ii) { QQuickItem *targetItem = d->targets.at(ii); @@ -1610,6 +1610,85 @@ void QQuickItemPrivate::setLayoutMirror(bool mirror) } } +/*! + \qmltype EnterKey + \instantiates QQuickEnterKeyAttached + \inqmlmodule QtQuick + \ingroup qtquick-input + \since 5.6 + \brief Provides a property to manipulate the appearance of Enter key on + an on-screen keyboard. + + The EnterKey attached property is used to manipulate the appearance and + behavior of the Enter key on an on-screen keyboard. +*/ + +/*! + \qmlproperty enumeration QtQuick::EnterKey::type + + Holds the type of the Enter key. + + \note Not all of these values are supported on all platforms. For + unsupported values the default key is used instead. + + \value Qt.EnterKeyDefault The default Enter key. This can be either a + button to accept the input and close the + keyboard, or a \e Return button to enter a + newline in case of a multi-line input field. + + \value Qt.EnterKeyReturn Show a \e Return button that inserts a + newline. + + \value Qt.EnterKeyDone Show a \e {"Done"} button. Typically, the + keyboard is expected to close when the button + is pressed. + + \value Qt.EnterKeyGo Show a \e {"Go"} button. Typically used in an + address bar when entering a URL. + + \value Qt.EnterKeySend Show a \e {"Send"} button. + + \value Qt.EnterKeySearch Show a \e {"Search"} button. + + \value Qt.EnterKeyNext Show a \e {"Next"} button. Typically used in a + form to allow navigating to the next input + field without the keyboard closing. + + \value Qt.EnterKeyPrevious Show a \e {"Previous"} button. +*/ + +QQuickEnterKeyAttached::QQuickEnterKeyAttached(QObject *parent) + : QObject(parent), itemPrivate(0), keyType(Qt::EnterKeyDefault) +{ + if (QQuickItem *item = qobject_cast<QQuickItem*>(parent)) { + itemPrivate = QQuickItemPrivate::get(item); + itemPrivate->extra.value().enterKeyAttached = this; + } else + qmlInfo(parent) << tr("EnterKey attached property only works with Items"); +} + +QQuickEnterKeyAttached *QQuickEnterKeyAttached::qmlAttachedProperties(QObject *object) +{ + return new QQuickEnterKeyAttached(object); +} + +Qt::EnterKeyType QQuickEnterKeyAttached::type() const +{ + return keyType; +} + +void QQuickEnterKeyAttached::setType(Qt::EnterKeyType type) +{ + if (keyType != type) { + keyType = type; +#ifndef QT_NO_IM + if (itemPrivate && itemPrivate->activeFocus) + QGuiApplication::inputMethod()->update(Qt::ImEnterKeyType); +#endif + typeChanged(); + } +} + void QQuickItemPrivate::setAccessible() { isAccessible = true; @@ -2345,6 +2424,50 @@ bool QQuickItemPrivate::focusNextPrev(QQuickItem *item, bool forward) return true; } +QQuickItem *QQuickItemPrivate::nextTabChildItem(const QQuickItem *item, int start) +{ + if (!item) { + qWarning() << "QQuickItemPrivate::nextTabChildItem called with null item."; + return Q_NULLPTR; + } + const QList<QQuickItem *> &children = item->childItems(); + const int count = children.count(); + if (start < 0 || start >= count) { + qWarning() << "QQuickItemPrivate::nextTabChildItem: Start index value out of range for item" << item; + return Q_NULLPTR; + } + while (start < count) { + QQuickItem *child = children.at(start); + if (!child->d_func()->isTabFence) + return child; + ++start; + } + return Q_NULLPTR; +} + +QQuickItem *QQuickItemPrivate::prevTabChildItem(const QQuickItem *item, int start) +{ + if (!item) { + qWarning() << "QQuickItemPrivate::prevTabChildItem called with null item."; + return Q_NULLPTR; + } + const QList<QQuickItem *> &children = item->childItems(); + const int count = children.count(); + if (start == -1) + start = count - 1; + if (start < 0 || start >= count) { + qWarning() << "QQuickItemPrivate::prevTabChildItem: Start index value out of range for item" << item; + return Q_NULLPTR; + } + while (start >= 0) { + QQuickItem *child = children.at(start); + if (!child->d_func()->isTabFence) + return child; + --start; + } + return Q_NULLPTR; +} + QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, bool forward) { Q_ASSERT(item); @@ -2367,7 +2490,6 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo from = item->parentItem(); } bool skip = false; - const QQuickItem * const originalItem = item; QQuickItem * startItem = item; QQuickItem * firstFromItem = from; QQuickItem *current = item; @@ -2376,46 +2498,53 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo QQuickItem *last = current; bool hasChildren = !current->childItems().isEmpty() && current->isEnabled() && current->isVisible(); + QQuickItem *firstChild = Q_NULLPTR; + QQuickItem *lastChild = Q_NULLPTR; + if (hasChildren) { + firstChild = nextTabChildItem(current, 0); + if (!firstChild) + hasChildren = false; + else + lastChild = prevTabChildItem(current, -1); + } + bool isTabFence = current->d_func()->isTabFence; // coming from parent: check children if (hasChildren && from == current->parentItem()) { if (forward) { - current = current->childItems().first(); + current = firstChild; } else { - current = current->childItems().last(); + current = lastChild; if (!current->childItems().isEmpty()) skip = true; } - } else if (hasChildren && forward && from != current->childItems().last()) { + } else if (hasChildren && forward && from != lastChild) { // not last child going forwards int nextChild = current->childItems().indexOf(from) + 1; - current = current->childItems().at(nextChild); - } else if (hasChildren && !forward && from != current->childItems().first()) { + current = nextTabChildItem(current, nextChild); + } else if (hasChildren && !forward && from != firstChild) { // not first child going backwards int prevChild = current->childItems().indexOf(from) - 1; - current = current->childItems().at(prevChild); + current = prevTabChildItem(current, prevChild); if (!current->childItems().isEmpty()) skip = true; // back to the parent - } else if (current->parentItem()) { - current = current->parentItem(); + } else if (QQuickItem *parent = !isTabFence ? current->parentItem() : Q_NULLPTR) { // we would evaluate the parent twice, thus we skip if (forward) { skip = true; - } else if (!forward && !current->childItems().isEmpty()) { - if (last != current->childItems().first()) { - skip = true; - } else if (last == current->childItems().first()) { - if (current->isFocusScope() && current->activeFocusOnTab() && current->hasActiveFocus()) + } else if (QQuickItem *firstSibling = !forward ? nextTabChildItem(parent, 0) : Q_NULLPTR) { + if (last != firstSibling + || (parent->isFocusScope() && parent->activeFocusOnTab() && parent->hasActiveFocus())) skip = true; - } } + current = parent; } else if (hasChildren) { // Wrap around after checking all items forward if (forward) { - current = current->childItems().first(); + current = firstChild; } else { - current = current->childItems().last(); + current = lastChild; if (!current->childItems().isEmpty()) skip = true; } @@ -2423,9 +2552,9 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo from = last; if (current == startItem && from == firstFromItem) { // wrapped around, avoid endless loops - if (originalItem == contentItem) { + if (item == contentItem) { qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return contentItem"; - return item->window()->contentItem(); + return item; } else { qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return " << startItem; return startItem; @@ -2475,7 +2604,7 @@ void QQuickItem::setParentItem(QQuickItem *parentItem) QQuickItem *itemAncestor = parentItem; while (itemAncestor != 0) { if (itemAncestor == this) { - qWarning("QQuickItem::setParentItem: Parent is already part of this items subtree."); + qWarning() << "QQuickItem::setParentItem: Parent" << parentItem << "is already part of the subtree of" << this; return; } itemAncestor = itemAncestor->parentItem(); @@ -2587,7 +2716,15 @@ void QQuickItem::setParentItem(QQuickItem *parentItem) /*! Moves the specified \a sibling item to the index before this item - within the visual stacking order. + within the list of children. The order of children affects both the + visual stacking order and tab focus navigation order. + + Assuming the z values of both items are the same, this will cause \a + sibling to be rendered above this item. + + If both items have activeFocusOnTab set to \c true, this will also cause + the tab focus order to change, with \a sibling receiving focus after this + item. The given \a sibling must be a sibling of this item; that is, they must have the same immediate \l parent. @@ -2623,7 +2760,15 @@ void QQuickItem::stackBefore(const QQuickItem *sibling) /*! Moves the specified \a sibling item to the index after this item - within the visual stacking order. + within the list of children. The order of children affects both the + visual stacking order and tab focus navigation order. + + Assuming the z values of both items are the same, this will cause \a + sibling to be rendered below this item. + + If both items have activeFocusOnTab set to \c true, this will also cause + the tab focus order to change, with \a sibling receiving focus before this + item. The given \a sibling must be a sibling of this item; that is, they must have the same immediate \l parent. @@ -2778,7 +2923,7 @@ void QQuickItemPrivate::refWindow(QQuickWindow *c) window = c; if (polishScheduled) - QQuickWindowPrivate::get(window)->itemsToPolish.insert(q); + QQuickWindowPrivate::get(window)->itemsToPolish.append(q); if (!parentItem) QQuickWindowPrivate::get(window)->parentlessItems.insert(q); @@ -2810,7 +2955,7 @@ void QQuickItemPrivate::derefWindow() removeFromDirtyList(); QQuickWindowPrivate *c = QQuickWindowPrivate::get(window); if (polishScheduled) - c->itemsToPolish.remove(q); + c->itemsToPolish.removeOne(q); QMutableHashIterator<int, QQuickItem *> itemTouchMapIt(c->itemForTouchPointId); while (itemTouchMapIt.hasNext()) { if (itemTouchMapIt.next().value() == q) @@ -2949,6 +3094,8 @@ QQuickItemPrivate::QQuickItemPrivate() , activeFocusOnTab(false) , implicitAntialiasing(false) , antialiasingValid(false) + , isTabFence(false) + , replayingPressEvent(false) , dirtyAttributes(0) , nextDirtyItem(0) , prevDirtyItem(0) @@ -3962,6 +4109,11 @@ QVariant QQuickItem::inputMethodQuery(Qt::InputMethodQuery query) const case Qt::ImPreferredLanguage: if (d->extra.isAllocated() && d->extra->keyHandler) v = d->extra->keyHandler->inputMethodQuery(query); + break; + case Qt::ImEnterKeyType: + if (d->extra.isAllocated() && d->extra->enterKeyAttached) + v = d->extra->enterKeyAttached->type(); + break; default: break; } @@ -4104,7 +4256,7 @@ void QQuickItem::polish() if (d->window) { QQuickWindowPrivate *p = QQuickWindowPrivate::get(d->window); bool maybeupdate = p->itemsToPolish.isEmpty(); - p->itemsToPolish.insert(this); + p->itemsToPolish.append(this); if (maybeupdate) d->window->maybeUpdate(); } } @@ -4126,8 +4278,10 @@ void QQuickItem::polish() */ void QQuickItem::mapFromItem(QQmlV4Function *args) const { - if (args->length() == 0) + if (args->length() != 3 && args->length() != 5) { + args->v4engine()->throwTypeError(); return; + } QV4::ExecutionEngine *v4 = args->v4engine(); QV4::Scope scope(v4); @@ -4143,19 +4297,33 @@ void QQuickItem::mapFromItem(QQmlV4Function *args) const if (!itemObj && !item->isNull()) { qmlInfo(this) << "mapFromItem() given argument \"" << item->toQStringNoThrow() << "\" which is neither null nor an Item"; + args->v4engine()->throwTypeError(); return; } - QV4::ScopedValue v(scope); + QV4::ScopedValue vx(scope, (*args)[1]); + QV4::ScopedValue vy(scope, (*args)[2]); - qreal x = (args->length() > 1) ? (v = (*args)[1])->asDouble() : 0; - qreal y = (args->length() > 2) ? (v = (*args)[2])->asDouble() : 0; + if (!vx->isNumber() || !vy->isNumber()) { + args->v4engine()->throwTypeError(); + return; + } + + qreal x = vx->asDouble(); + qreal y = vy->asDouble(); QVariant result; if (args->length() > 3) { - qreal w = (v = (*args)[3])->asDouble(); - qreal h = (args->length() > 4) ? (v = (*args)[4])->asDouble() : 0; + QV4::ScopedValue vw(scope, (*args)[3]); + QV4::ScopedValue vh(scope, (*args)[4]); + if (!vw->isNumber() || !vh->isNumber()) { + args->v4engine()->throwTypeError(); + return; + } + qreal w = vw->asDouble(); + qreal h = vh->asDouble(); + result = mapRectFromItem(itemObj, QRectF(x, y, w, h)); } else { result = mapFromItem(itemObj, QPointF(x, y)); @@ -4198,8 +4366,10 @@ QTransform QQuickItem::itemTransform(QQuickItem *other, bool *ok) const */ void QQuickItem::mapToItem(QQmlV4Function *args) const { - if (args->length() == 0) + if (args->length() != 3 && args->length() != 5) { + args->v4engine()->throwTypeError(); return; + } QV4::ExecutionEngine *v4 = args->v4engine(); QV4::Scope scope(v4); @@ -4215,18 +4385,32 @@ void QQuickItem::mapToItem(QQmlV4Function *args) const if (!itemObj && !item->isNull()) { qmlInfo(this) << "mapToItem() given argument \"" << item->toQStringNoThrow() << "\" which is neither null nor an Item"; + args->v4engine()->throwTypeError(); return; } - QV4::ScopedValue v(scope); - QVariant result; + QV4::ScopedValue vx(scope, (*args)[1]); + QV4::ScopedValue vy(scope, (*args)[2]); + + if (!vx->isNumber() || !vy->isNumber()) { + args->v4engine()->throwTypeError(); + return; + } + + qreal x = vx->asDouble(); + qreal y = vy->asDouble(); - qreal x = (args->length() > 1) ? (v = (*args)[1])->asDouble() : 0; - qreal y = (args->length() > 2) ? (v = (*args)[2])->asDouble() : 0; + QVariant result; if (args->length() > 3) { - qreal w = (v = (*args)[3])->asDouble(); - qreal h = (args->length() > 4) ? (v = (*args)[4])->asDouble() : 0; + QV4::ScopedValue vw(scope, (*args)[3]); + QV4::ScopedValue vh(scope, (*args)[4]); + if (!vw->isNumber() || !vh->isNumber()) { + args->v4engine()->throwTypeError(); + return; + } + qreal w = vw->asDouble(); + qreal h = vh->asDouble(); result = mapRectToItem(itemObj, QRectF(x, y, w, h)); } else { @@ -5578,7 +5762,7 @@ QString QQuickItemPrivate::dirtyToString() const { #define DIRTY_TO_STRING(value) if (dirtyAttributes & value) { \ if (!rv.isEmpty()) \ - rv.append(QLatin1String("|")); \ + rv.append(QLatin1Char('|')); \ rv.append(QLatin1String(#value)); \ } @@ -7408,6 +7592,7 @@ QQuickItemLayer::QQuickItemLayer(QQuickItem *item) , m_effectComponent(0) , m_effect(0) , m_effectSource(0) + , m_textureMirroring(QQuickShaderEffectSource::MirrorVertically) { } @@ -7481,6 +7666,7 @@ void QQuickItemLayer::activate() m_effectSource->setMipmap(m_mipmap); m_effectSource->setWrapMode(m_wrapMode); m_effectSource->setFormat(m_format); + m_effectSource->setTextureMirroring(m_textureMirroring); if (m_effectComponent) activateEffect(); @@ -7745,6 +7931,35 @@ void QQuickItemLayer::setWrapMode(QQuickShaderEffectSource::WrapMode mode) } /*! + \qmlproperty enumeration QtQuick::Item::layer.textureMirroring + \since 5.6 + + This property defines how the generated OpenGL texture should be mirrored. + The default value is \c{ShaderEffectSource.MirrorVertically}. + Custom mirroring can be useful if the generated texture is directly accessed by custom shaders, + such as those specified by ShaderEffect. If no effect is specified for the layered + item, mirroring has no effect on the UI representation of the item. + + \list + \li ShaderEffectSource.NoMirroring - No mirroring + \li ShaderEffectSource.MirrorHorizontally - The generated texture is flipped along X-axis. + \li ShaderEffectSource.MirrorVertically - The generated texture is flipped along Y-axis. + \endlist + */ + +void QQuickItemLayer::setTextureMirroring(QQuickShaderEffectSource::TextureMirroring mirroring) +{ + if (mirroring == m_textureMirroring) + return; + m_textureMirroring = mirroring; + + if (m_effectSource) + m_effectSource->setTextureMirroring(m_textureMirroring); + + emit textureMirroringChanged(mirroring); +} + +/*! \qmlproperty string QtQuick::Item::layer.samplerName Holds the name of the effect's source texture property. @@ -7856,6 +8071,7 @@ void QQuickItemLayer::updateMatrix() QQuickItemPrivate::ExtraData::ExtraData() : z(0), scale(1), rotation(0), opacity(1), contents(0), screenAttached(0), layoutDirectionAttached(0), + enterKeyAttached(0), keyHandler(0), layer(0), effectRefCount(0), hideRefCount(0), opacityNode(0), clipNode(0), rootNode(0), @@ -7864,6 +8080,19 @@ QQuickItemPrivate::ExtraData::ExtraData() { } + +#ifndef QT_NO_ACCESSIBILITY +QAccessible::Role QQuickItemPrivate::accessibleRole() const +{ + Q_Q(const QQuickItem); + QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, false)); + if (accessibleAttached) + return accessibleAttached->role(); + + return QAccessible::NoRole; +} +#endif + QT_END_NAMESPACE #include <moc_qquickitem.cpp> |