diff options
Diffstat (limited to 'src/quick/items')
26 files changed, 691 insertions, 74 deletions
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp index ab5170cd65..6f14bf15fe 100644 --- a/src/quick/items/qquickanimatedimage.cpp +++ b/src/quick/items/qquickanimatedimage.cpp @@ -47,8 +47,10 @@ #include <QtQml/qqmlfile.h> #include <QtQml/qqmlengine.h> #include <QtGui/qmovie.h> +#ifndef QT_NO_NETWORK #include <QtNetwork/qnetworkrequest.h> #include <QtNetwork/qnetworkreply.h> +#endif QT_BEGIN_NAMESPACE @@ -144,8 +146,10 @@ QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent) QQuickAnimatedImage::~QQuickAnimatedImage() { Q_D(QQuickAnimatedImage); +#ifndef QT_NO_NETWORK if (d->reply) d->reply->deleteLater(); +#endif delete d->_movie; qDeleteAll(d->frameMap); d->frameMap.clear(); @@ -264,10 +268,12 @@ void QQuickAnimatedImage::setSource(const QUrl &url) if (url == d->url) return; +#ifndef QT_NO_NETWORK if (d->reply) { d->reply->deleteLater(); d->reply = 0; } +#endif d->setImage(QImage()); qDeleteAll(d->frameMap); @@ -319,6 +325,7 @@ void QQuickAnimatedImage::load() d->_movie = new QMovie(lf); movieRequestFinished(); } else { +#ifndef QT_NO_NETWORK if (d->status != Loading) { d->status = Loading; emit statusChanged(d->status); @@ -335,6 +342,7 @@ void QQuickAnimatedImage::load() this, SLOT(movieRequestFinished())); QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(requestProgress(qint64,qint64))); +#endif } } } @@ -343,8 +351,10 @@ void QQuickAnimatedImage::load() void QQuickAnimatedImage::movieRequestFinished() { + Q_D(QQuickAnimatedImage); +#ifndef QT_NO_NETWORK if (d->reply) { d->redirectCount++; if (d->redirectCount < ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION) { @@ -360,6 +370,7 @@ void QQuickAnimatedImage::movieRequestFinished() d->redirectCount=0; d->_movie = new QMovie(d->reply); } +#endif if (!d->_movie->isValid()) { qmlInfo(this) << "Error Reading Animated Image File " << d->url.toString(); diff --git a/src/quick/items/qquickanimatedimage_p_p.h b/src/quick/items/qquickanimatedimage_p_p.h index 6d32f1071f..ed735d1c9c 100644 --- a/src/quick/items/qquickanimatedimage_p_p.h +++ b/src/quick/items/qquickanimatedimage_p_p.h @@ -58,7 +58,9 @@ QT_BEGIN_NAMESPACE class QMovie; +#ifndef QT_NO_NETWORK class QNetworkReply; +#endif class QQuickAnimatedImagePrivate : public QQuickImagePrivate { @@ -66,7 +68,11 @@ class QQuickAnimatedImagePrivate : public QQuickImagePrivate public: QQuickAnimatedImagePrivate() - : playing(true), paused(false), preset_currentframe(0), _movie(0), reply(0), redirectCount(0), oldPlaying(false), currentSourceSize(0, 0) + : playing(true), paused(false), preset_currentframe(0), _movie(0), oldPlaying(false) +#ifndef QT_NO_NETWORK + , reply(0), redirectCount(0) +#endif + , currentSourceSize(0, 0) { } @@ -76,9 +82,11 @@ public: bool paused; int preset_currentframe; QMovie *_movie; + bool oldPlaying; +#ifndef QT_NO_NETWORK QNetworkReply *reply; int redirectCount; - bool oldPlaying; +#endif QMap<int, QQuickPixmap *> frameMap; QSize currentSourceSize; }; diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp index 66f414d816..b3a35e6219 100644 --- a/src/quick/items/qquickborderimage.cpp +++ b/src/quick/items/qquickborderimage.cpp @@ -43,7 +43,9 @@ #include <QtQml/qqmlinfo.h> #include <QtQml/qqmlfile.h> #include <QtQml/qqmlengine.h> +#ifndef QT_NO_NETWORK #include <QtNetwork/qnetworkreply.h> +#endif #include <QtCore/qfile.h> #include <QtCore/qmath.h> #include <QtGui/qguiapplication.h> @@ -169,9 +171,11 @@ QQuickBorderImage::QQuickBorderImage(QQuickItem *parent) QQuickBorderImage::~QQuickBorderImage() { +#ifndef QT_NO_NETWORK Q_D(QQuickBorderImage); if (d->sciReply) d->sciReply->deleteLater(); +#endif } /*! @@ -270,10 +274,12 @@ void QQuickBorderImage::setSource(const QUrl &url) if (url == d->url) return; +#ifndef QT_NO_NETWORK if (d->sciReply) { d->sciReply->deleteLater(); d->sciReply = 0; } +#endif d->url = url; d->sciurl = QUrl(); @@ -311,6 +317,7 @@ void QQuickBorderImage::load() setGridScaledImage(QQuickGridScaledImage(&file)); return; } else { +#ifndef QT_NO_NETWORK if (d->progress != 0.0) { d->progress = 0.0; emit progressChanged(d->progress); @@ -320,6 +327,7 @@ void QQuickBorderImage::load() d->sciReply = qmlEngine(this)->networkAccessManager()->get(req); qmlobject_connect(d->sciReply, QNetworkReply, SIGNAL(finished()), this, QQuickBorderImage, SLOT(sciRequestFinished())) +#endif } } else { QQuickPixmap::Options options; @@ -529,6 +537,7 @@ void QQuickBorderImage::requestFinished() pixmapChange(); } +#ifndef QT_NO_NETWORK #define BORDERIMAGE_MAX_REDIRECT 16 void QQuickBorderImage::sciRequestFinished() @@ -558,12 +567,59 @@ void QQuickBorderImage::sciRequestFinished() setGridScaledImage(sci); } } +#endif // QT_NO_NETWORK void QQuickBorderImage::doUpdate() { update(); } +void QQuickBorderImagePrivate::calculateRects(const QQuickScaleGrid *border, + const QSize &sourceSize, + const QSizeF &targetSize, + int horizontalTileMode, + int verticalTileMode, + qreal devicePixelRatio, + QRectF *targetRect, + QRectF *innerTargetRect, + QRectF *innerSourceRect, + QRectF *subSourceRect) +{ + *innerSourceRect = QRectF(0, 0, 1, 1); + *targetRect = QRectF(0, 0, targetSize.width(), targetSize.height()); + *innerTargetRect = *targetRect; + + if (border) { + *innerSourceRect = QRectF(border->left() * devicePixelRatio / qreal(sourceSize.width()), + border->top() * devicePixelRatio / qreal(sourceSize.height()), + qMax<qreal>(0, sourceSize.width() - (border->right() + border->left()) * devicePixelRatio) / sourceSize.width(), + qMax<qreal>(0, sourceSize.height() - (border->bottom() + border->top()) * devicePixelRatio) / sourceSize.height()); + *innerTargetRect = QRectF(border->left(), + border->top(), + qMax<qreal>(0, targetSize.width() - (border->right() + border->left())), + qMax<qreal>(0, targetSize.height() - (border->bottom() + border->top()))); + } + + qreal hTiles = 1; + qreal vTiles = 1; + const QSizeF innerTargetSize = innerTargetRect->size() * devicePixelRatio; + if (innerSourceRect->width() != 0 + && horizontalTileMode != QQuickBorderImage::Stretch) { + hTiles = innerTargetSize.width() / qreal(innerSourceRect->width() * sourceSize.width()); + if (horizontalTileMode == QQuickBorderImage::Round) + hTiles = qCeil(hTiles); + } + if (innerSourceRect->height() != 0 + && verticalTileMode != QQuickBorderImage::Stretch) { + vTiles = innerTargetSize.height() / qreal(innerSourceRect->height() * sourceSize.height()); + if (verticalTileMode == QQuickBorderImage::Round) + vTiles = qCeil(vTiles); + } + + *subSourceRect = QRectF(0, 0, hTiles, vTiles); +} + + QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { Q_D(QQuickBorderImage); @@ -588,45 +644,25 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat node->setTexture(texture); // Don't implicitly create the scalegrid in the rendering thread... - QRectF innerSourceRect(0, 0, 1, 1); - QRectF targetRect(0, 0, width(), height()); - QRectF innerTargetRect = targetRect; - if (d->border) { - const QQuickScaleGrid *border = d->getScaleGrid(); - innerSourceRect = QRectF(border->left() * d->devicePixelRatio / qreal(d->pix.width()), - border->top() * d->devicePixelRatio / qreal(d->pix.height()), - qMax<qreal>(0, d->pix.width() - (border->right() + border->left()) * d->devicePixelRatio) / d->pix.width(), - qMax<qreal>(0, d->pix.height() - (border->bottom() + border->top()) * d->devicePixelRatio) / d->pix.height()); - innerTargetRect = QRectF(border->left(), - border->top(), - qMax<qreal>(0, width() - (border->right() + border->left())), - qMax<qreal>(0, height() - (border->bottom() + border->top()))); - } - qreal hTiles = 1; - qreal vTiles = 1; - const QSizeF innerTargetSize = innerTargetRect.size() * d->devicePixelRatio; - if (innerSourceRect.width() != 0 - && d->horizontalTileMode != QQuickBorderImage::Stretch) { - hTiles = innerTargetSize.width() / qreal(innerSourceRect.width() * d->pix.width()); - if (d->horizontalTileMode == QQuickBorderImage::Round) - hTiles = qCeil(hTiles); - } - if (innerSourceRect.height() != 0 - && d->verticalTileMode != QQuickBorderImage::Stretch) { - vTiles = innerTargetSize.height() / qreal(innerSourceRect.height() * d->pix.height()); - if (d->verticalTileMode == QQuickBorderImage::Round) - vTiles = qCeil(vTiles); - } + QRectF targetRect; + QRectF innerTargetRect; + QRectF innerSourceRect; + QRectF subSourceRect; + d->calculateRects(d->border, + QSize(d->pix.width(), d->pix.height()), QSizeF(width(), height()), + d->horizontalTileMode, d->verticalTileMode, d->devicePixelRatio, + &targetRect, &innerTargetRect, + &innerSourceRect, &subSourceRect); node->setTargetRect(targetRect); node->setInnerSourceRect(innerSourceRect); node->setInnerTargetRect(innerTargetRect); - node->setSubSourceRect(QRectF(0, 0, hTiles, vTiles)); + node->setSubSourceRect(subSourceRect); node->setMirror(d->mirror); node->setMipmapFiltering(QSGTexture::None); node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest); - if (innerSourceRect == QRectF(0, 0, 1, 1) && (vTiles > 1 || hTiles > 1)) { + if (innerSourceRect == QRectF(0, 0, 1, 1) && (subSourceRect.width() > 1 || subSourceRect.height() > 1)) { node->setHorizontalWrapMode(QSGTexture::Repeat); node->setVerticalWrapMode(QSGTexture::Repeat); } else { diff --git a/src/quick/items/qquickborderimage_p.h b/src/quick/items/qquickborderimage_p.h index 7f8b172a21..f2764660f6 100644 --- a/src/quick/items/qquickborderimage_p.h +++ b/src/quick/items/qquickborderimage_p.h @@ -101,7 +101,9 @@ private: private Q_SLOTS: void doUpdate(); void requestFinished() Q_DECL_OVERRIDE; +#ifndef QT_NO_NETWORK void sciRequestFinished(); +#endif private: Q_DISABLE_COPY(QQuickBorderImage) diff --git a/src/quick/items/qquickborderimage_p_p.h b/src/quick/items/qquickborderimage_p_p.h index 478de88a52..56fbbab049 100644 --- a/src/quick/items/qquickborderimage_p_p.h +++ b/src/quick/items/qquickborderimage_p_p.h @@ -58,17 +58,20 @@ QT_BEGIN_NAMESPACE +#ifndef QT_NO_NETWORK class QNetworkReply; +#endif class QQuickBorderImagePrivate : public QQuickImageBasePrivate { Q_DECLARE_PUBLIC(QQuickBorderImage) public: QQuickBorderImagePrivate() - : border(0), sciReply(0), - horizontalTileMode(QQuickBorderImage::Stretch), - verticalTileMode(QQuickBorderImage::Stretch), - redirectCount(0), pixmapChanged(false) + : border(0), horizontalTileMode(QQuickBorderImage::Stretch), + verticalTileMode(QQuickBorderImage::Stretch), pixmapChanged(false) +#ifndef QT_NO_NETWORK + , sciReply(0), redirectCount(0) +#endif { } @@ -88,14 +91,27 @@ public: return border; } + static void calculateRects(const QQuickScaleGrid *border, + const QSize &sourceSize, + const QSizeF &targetSize, + int horizontalTileMode, + int verticalTileMode, + qreal devicePixelRatio, + QRectF *targetRect, + QRectF *innerTargetRect, + QRectF *innerSourceRect, + QRectF *subSourceRect); + QQuickScaleGrid *border; QUrl sciurl; - QNetworkReply *sciReply; QQuickBorderImage::TileMode horizontalTileMode; QQuickBorderImage::TileMode verticalTileMode; - int redirectCount; - bool pixmapChanged : 1; + +#ifndef QT_NO_NETWORK + QNetworkReply *sciReply; + int redirectCount; +#endif }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp index 9a24d7a8a0..cc30199253 100644 --- a/src/quick/items/qquickdrag.cpp +++ b/src/quick/items/qquickdrag.cpp @@ -45,6 +45,7 @@ #include <private/qquickitem_p.h> #include <QtQuick/private/qquickevents_p_p.h> #include <private/qquickitemchangelistener_p.h> +#include <private/qquickpixmapcache_p.h> #include <private/qv8engine_p.h> #include <private/qv4scopedvalue_p.h> #include <QtCore/qmimedata.h> @@ -110,6 +111,8 @@ public: bool eventQueued : 1; bool overrideActions : 1; QPointF hotSpot; + QUrl imageSource; + QQuickPixmap pixmapLoader; QStringList keys; QVariantMap externalMimeData; QQuickDrag::DragType dragType; @@ -409,6 +412,43 @@ void QQuickDragAttached::setHotSpot(const QPointF &hotSpot) } /*! + \qmlattachedproperty QUrl QtQuick::Drag::imageSource + \since 5.8 + + This property holds the URL of the image which will be used to represent + the data during the drag and drop operation. Changing this property after + the drag operation has started will have no effect. + + The example below uses an item's contents as a drag image: + + \snippet qml/externaldrag.qml 0 + + \sa Item::grabToImage() +*/ + +QUrl QQuickDragAttached::imageSource() const +{ + Q_D(const QQuickDragAttached); + return d->imageSource; +} + +void QQuickDragAttached::setImageSource(const QUrl &url) +{ + Q_D(QQuickDragAttached); + if (d->imageSource != url) { + d->imageSource = url; + + if (url.isEmpty()) { + d->pixmapLoader.clear(); + } else { + d->pixmapLoader.load(qmlEngine(this), url); + } + + Q_EMIT imageSourceChanged(); + } +} + +/*! \qmlattachedproperty stringlist QtQuick::Drag::keys This property holds a list of keys that can be used by a DropArea to filter drag events. @@ -727,9 +767,9 @@ Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedAct mimeData->setData(it.key(), it.value().toString().toUtf8()); drag->setMimeData(mimeData); - - // TODO: how to handle drag image? - // drag->setPixmap(iconPixmap); + if (pixmapLoader.isReady()) { + drag->setPixmap(QPixmap::fromImage(pixmapLoader.image())); + } emit q->dragStarted(); diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h index c1695e49f0..17721251d9 100644 --- a/src/quick/items/qquickdrag_p.h +++ b/src/quick/items/qquickdrag_p.h @@ -58,6 +58,7 @@ #include <QtCore/qmimedata.h> #include <QtCore/qstringlist.h> +#include <QtCore/qurl.h> #ifndef QT_NO_DRAGANDDROP @@ -247,6 +248,7 @@ class QQuickDragAttached : public QObject Q_PROPERTY(QObject *source READ source WRITE setSource NOTIFY sourceChanged RESET resetSource) Q_PROPERTY(QObject *target READ target NOTIFY targetChanged) Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot NOTIFY hotSpotChanged) + Q_PROPERTY(QUrl imageSource READ imageSource WRITE setImageSource NOTIFY imageSourceChanged REVISION 8) Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged) Q_PROPERTY(QVariantMap mimeData READ mimeData WRITE setMimeData NOTIFY mimeDataChanged) Q_PROPERTY(Qt::DropActions supportedActions READ supportedActions WRITE setSupportedActions NOTIFY supportedActionsChanged) @@ -268,6 +270,9 @@ public: QPointF hotSpot() const; void setHotSpot(const QPointF &hotSpot); + QUrl imageSource() const; + void setImageSource(const QUrl &url); + QStringList keys() const; void setKeys(const QStringList &keys); @@ -300,6 +305,7 @@ Q_SIGNALS: void sourceChanged(); void targetChanged(); void hotSpotChanged(); + void imageSourceChanged(); void keysChanged(); void mimeDataChanged(); void supportedActionsChanged(); diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 95b4e09aa5..d6fdf5795e 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -84,6 +84,8 @@ QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(DBG_MOUSE_TARGET) + #ifndef QT_NO_DEBUG static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK"); #endif @@ -2889,6 +2891,8 @@ void QQuickItemPrivate::addChild(QQuickItem *child) if (childPrivate->hasCursorInChild && !hasCursorInChild) setHasCursorInChild(true); #endif + if (childPrivate->hasHoverInChild && !hasHoverInChild) + setHasHoverInChild(true); markSortedChildrenDirty(child); dirty(QQuickItemPrivate::ChildrenChanged); @@ -2914,6 +2918,8 @@ void QQuickItemPrivate::removeChild(QQuickItem *child) if (childPrivate->hasCursorInChild && hasCursorInChild) setHasCursorInChild(false); #endif + if (childPrivate->hasHoverInChild && hasHoverInChild) + setHasHoverInChild(false); markSortedChildrenDirty(child); dirty(QQuickItemPrivate::ChildrenChanged); @@ -3136,6 +3142,7 @@ QQuickItemPrivate::QQuickItemPrivate() , culled(false) , hasCursor(false) , hasCursorInChild(false) + , hasHoverInChild(false) , activeFocusOnTab(false) , implicitAntialiasing(false) , antialiasingValid(false) @@ -6940,7 +6947,7 @@ void QQuickItem::setAcceptedMouseButtons(Qt::MouseButtons buttons) } /*! - Returns whether mouse events of this item's children should be filtered + Returns whether mouse and touch events of this item's children should be filtered through this item. \sa setFiltersChildMouseEvents(), childMouseEventFilter() @@ -6952,7 +6959,7 @@ bool QQuickItem::filtersChildMouseEvents() const } /*! - Sets whether mouse events of this item's children should be filtered + Sets whether mouse and touch events of this item's children should be filtered through this item. If \a filter is true, childMouseEventFilter() will be called when @@ -7003,6 +7010,7 @@ void QQuickItem::setAcceptHoverEvents(bool enabled) { Q_D(QQuickItem); d->hoverEnabled = enabled; + d->setHasHoverInChild(enabled); } void QQuickItemPrivate::setHasCursorInChild(bool hasCursor) @@ -7030,6 +7038,29 @@ void QQuickItemPrivate::setHasCursorInChild(bool hasCursor) #endif } +void QQuickItemPrivate::setHasHoverInChild(bool hasHover) +{ + Q_Q(QQuickItem); + + // if we're asked to turn it off (because of a setAcceptHoverEvents call, or a node + // removal) then we should check our children and make sure it's really ok + // to turn it off. + if (!hasHover && hasHoverInChild) { + foreach (QQuickItem *otherChild, childItems) { + QQuickItemPrivate *otherChildPrivate = QQuickItemPrivate::get(otherChild); + if (otherChildPrivate->hasHoverInChild) + return; // nope! sorry, something else wants it kept on. + } + } + + hasHoverInChild = hasHover; + QQuickItem *parent = q->parentItem(); + if (parent) { + QQuickItemPrivate *parentPrivate = QQuickItemPrivate::get(parent); + parentPrivate->setHasHoverInChild(hasHover); + } +} + void QQuickItemPrivate::markObjects(QV4::ExecutionEngine *e) { Q_Q(QQuickItem); @@ -7155,6 +7186,7 @@ void QQuickItem::ungrabMouse() return; } + qCDebug(DBG_MOUSE_TARGET) << "ungrabMouse" << windowPriv->mouseGrabberItem << "-> null"; windowPriv->mouseGrabberItem = 0; QEvent ev(QEvent::UngrabMouse); @@ -7224,6 +7256,7 @@ void QQuickItem::grabTouchPoints(const QVector<int> &ids) QQuickItem *mouseGrabber = windowPriv->mouseGrabberItem; if (windowPriv->touchMouseId == ids.at(i) && mouseGrabber && mouseGrabber != this) { + qCDebug(DBG_MOUSE_TARGET) << "grabTouchPoints: grabber" << windowPriv->mouseGrabberItem << "-> null"; windowPriv->mouseGrabberItem = 0; QEvent ev(QEvent::UngrabMouse); d->window->sendEvent(mouseGrabber, &ev); diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index ad649e5b5f..854cbd769b 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -429,6 +429,7 @@ public: bool hasCursor:1; bool hasCursorInChild:1; // Bit 32 + bool hasHoverInChild:1; bool activeFocusOnTab:1; bool implicitAntialiasing:1; bool antialiasingValid:1; @@ -606,6 +607,7 @@ public: virtual void mirrorChange() {} void setHasCursorInChild(bool hasCursor); + void setHasHoverInChild(bool hasHover); // recursive helper to let a visual parent mark its visual children void markObjects(QV4::ExecutionEngine *e); diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 08d95119d7..0b413b76b6 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -211,6 +211,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickShaderEffectSource>("QtQuick", 2, 0, "ShaderEffectSource"); qmlRegisterUncreatableType<QQuickShaderEffectMesh>("QtQuick", 2, 0, "ShaderEffectMesh", QQuickShaderEffectMesh::tr("Cannot create instance of abstract class ShaderEffectMesh.")); qmlRegisterType<QQuickGridMesh>("QtQuick", 2, 0, "GridMesh"); + qmlRegisterType<QQuickBorderImageMesh>("QtQuick", 2, 8, "BorderImageMesh"); qmlRegisterUncreatableType<QQuickPaintedItem>("QtQuick", 2, 0, "PaintedItem", QQuickPaintedItem::tr("Cannot create instance of abstract class PaintedItem")); diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp index 74ca0f482a..b8c680433e 100644 --- a/src/quick/items/qquickrectangle.cpp +++ b/src/quick/items/qquickrectangle.cpp @@ -44,7 +44,6 @@ #include <private/qsgadaptationlayer_p.h> #include <QtGui/qpixmapcache.h> -#include <QtCore/qstringbuilder.h> #include <QtCore/qmath.h> #include <QtCore/qmetaobject.h> diff --git a/src/quick/items/qquickshadereffectmesh.cpp b/src/quick/items/qquickshadereffectmesh.cpp index 0811025654..842befac37 100644 --- a/src/quick/items/qquickshadereffectmesh.cpp +++ b/src/quick/items/qquickshadereffectmesh.cpp @@ -40,6 +40,9 @@ #include "qquickshadereffectmesh_p.h" #include <QtQuick/qsggeometry.h> #include "qquickshadereffect_p.h" +#include "qquickscalegrid_p_p.h" +#include "qquickborderimage_p_p.h" +#include <QtQuick/private/qsgdefaultimagenode_p.h> QT_BEGIN_NAMESPACE @@ -217,4 +220,184 @@ QSize QQuickGridMesh::resolution() const return m_resolution; } +/*! + \qmltype BorderImageMesh + \instantiates QQuickBorderImageMesh + \inqmlmodule QtQuick + \since 5.8 + \ingroup qtquick-effects + \brief Defines a mesh with vertices arranged like those of a BorderImage. + + BorderImageMesh provides BorderImage-like capabilities to a ShaderEffect + without the need for a potentially costly ShaderEffectSource. + + The following are functionally equivalent: + \qml + BorderImage { + id: borderImage + border { + left: 10 + right: 10 + top: 10 + bottom: 10 + } + source: "myImage.png" + visible: false + } + ShaderEffectSource { + id: effectSource + sourceItem: borderImage + visible: false + } + ShaderEffect { + property var source: effectSource + ... + } + \endqml + + \qml + Image { + id: image + source: "myImage.png" + visible: false + } + ShaderEffect { + property var source: image + mesh: BorderImageMesh { + border { + left: 10 + right: 10 + top: 10 + bottom: 10 + } + size: image.sourceSize + } + ... + } + \endqml + + But the BorderImageMesh version can typically be better optimized. +*/ +QQuickBorderImageMesh::QQuickBorderImageMesh(QObject *parent) + : QQuickShaderEffectMesh(parent), m_border(new QQuickScaleGrid(this)), + m_horizontalTileMode(QQuickBorderImageMesh::Stretch), + m_verticalTileMode(QQuickBorderImageMesh::Stretch) +{ +} + +QSGGeometry *QQuickBorderImageMesh::updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &/*attributes*/, const QRectF &srcRect, const QRectF &rect) +{ + QRectF innerSourceRect; + QRectF targetRect; + QRectF innerTargetRect; + QRectF subSourceRect; + + QQuickBorderImagePrivate::calculateRects(m_border, m_size, rect.size(), m_horizontalTileMode, m_verticalTileMode, 1, &targetRect, &innerTargetRect, &innerSourceRect, &subSourceRect); + + QRectF sourceRect = srcRect; + QRectF modifiedInnerSourceRect(sourceRect.x() + innerSourceRect.x() * sourceRect.width(), + sourceRect.y() + innerSourceRect.y() * sourceRect.height(), + innerSourceRect.width() * sourceRect.width(), + innerSourceRect.height() * sourceRect.height()); + + geometry = QSGDefaultImageNode::updateGeometry(targetRect, innerTargetRect, sourceRect, modifiedInnerSourceRect, subSourceRect, geometry); + + return geometry; +} + +/*! + \qmlpropertygroup QtQuick::BorderImageMesh::border + \qmlproperty int QtQuick::BorderImageMesh::border.left + \qmlproperty int QtQuick::BorderImageMesh::border.right + \qmlproperty int QtQuick::BorderImageMesh::border.top + \qmlproperty int QtQuick::BorderImageMesh::border.bottom + + The 4 border lines (2 horizontal and 2 vertical) break the image into 9 sections, + as shown below: + + \image declarative-scalegrid.png + + Each border line (left, right, top, and bottom) specifies an offset in pixels + from the respective edge of the mesh. By default, each border line has + a value of 0. + + For example, the following definition sets the bottom line 10 pixels up from + the bottom of the mesh: + + \qml + BorderImageMesh { + border.bottom: 10 + // ... + } + \endqml +*/ +QQuickScaleGrid *QQuickBorderImageMesh::border() +{ + return m_border; +} + +/*! + \qmlproperty size QtQuick::BorderImageMesh::size + + The base size of the mesh. This generally corresponds to the \l {Image::}{sourceSize} + of the image being used by the ShaderEffect. +*/ +QSize QQuickBorderImageMesh::size() const +{ + return m_size; +} + +void QQuickBorderImageMesh::setSize(const QSize &size) +{ + if (size == m_size) + return; + m_size = size; + Q_EMIT sizeChanged(); + Q_EMIT geometryChanged(); +} + +/*! + \qmlproperty enumeration QtQuick::BorderImageMesh::horizontalTileMode + \qmlproperty enumeration QtQuick::BorderImageMesh::verticalTileMode + + This property describes how to repeat or stretch the middle parts of an image. + + \list + \li BorderImage.Stretch - Scales the image to fit to the available area. + \li BorderImage.Repeat - Tile the image until there is no more space. May crop the last image. + \li BorderImage.Round - Like Repeat, but scales the images down to ensure that the last image is not cropped. + \endlist + + The default tile mode for each property is BorderImage.Stretch. +*/ + +QQuickBorderImageMesh::TileMode QQuickBorderImageMesh::horizontalTileMode() const +{ + return m_horizontalTileMode; +} + +void QQuickBorderImageMesh::setHorizontalTileMode(TileMode t) +{ + if (t == m_horizontalTileMode) + return; + m_horizontalTileMode = t; + Q_EMIT horizontalTileModeChanged(); + Q_EMIT geometryChanged(); +} + +QQuickBorderImageMesh::TileMode QQuickBorderImageMesh::verticalTileMode() const +{ + return m_verticalTileMode; +} + +void QQuickBorderImageMesh::setVerticalTileMode(TileMode t) +{ + if (t == m_verticalTileMode) + return; + + m_verticalTileMode = t; + Q_EMIT verticalTileModeChanged(); + Q_EMIT geometryChanged(); +} + QT_END_NAMESPACE diff --git a/src/quick/items/qquickshadereffectmesh_p.h b/src/quick/items/qquickshadereffectmesh_p.h index 7f9c95888c..34d3908140 100644 --- a/src/quick/items/qquickshadereffectmesh_p.h +++ b/src/quick/items/qquickshadereffectmesh_p.h @@ -100,6 +100,45 @@ private: QString m_log; }; +class QQuickScaleGrid; +class QQuickBorderImageMesh : public QQuickShaderEffectMesh +{ + Q_OBJECT + + Q_PROPERTY(QQuickScaleGrid *border READ border CONSTANT) + Q_PROPERTY(QSize size READ size WRITE setSize NOTIFY sizeChanged) + Q_PROPERTY(TileMode horizontalTileMode READ horizontalTileMode WRITE setHorizontalTileMode NOTIFY horizontalTileModeChanged) + Q_PROPERTY(TileMode verticalTileMode READ verticalTileMode WRITE setVerticalTileMode NOTIFY verticalTileModeChanged) +public: + QQuickBorderImageMesh(QObject *parent = 0); + QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &srcRect, const QRectF &rect) Q_DECL_OVERRIDE; + + QQuickScaleGrid *border(); + + enum TileMode { Stretch = Qt::StretchTile, Repeat = Qt::RepeatTile, Round = Qt::RoundTile }; + Q_ENUM(TileMode) + + QSize size() const; + void setSize(const QSize &size); + + TileMode horizontalTileMode() const; + void setHorizontalTileMode(TileMode); + + TileMode verticalTileMode() const; + void setVerticalTileMode(TileMode); + +Q_SIGNALS: + void sizeChanged(); + void horizontalTileModeChanged(); + void verticalTileModeChanged(); + +private: + QQuickScaleGrid *m_border; + QSize m_size; + TileMode m_horizontalTileMode; + TileMode m_verticalTileMode; +}; + inline QColor qt_premultiply_color(const QColor &c) { return QColor::fromRgbF(c.redF() * c.alphaF(), c.greenF() * c.alphaF(), c.blueF() * c.alphaF(), c.alphaF()); diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp index 60d5e3f6dd..6de613c5b0 100644 --- a/src/quick/items/qquickspriteengine.cpp +++ b/src/quick/items/qquickspriteengine.cpp @@ -111,7 +111,7 @@ QQuickSpriteEngine::QQuickSpriteEngine(QObject *parent) } QQuickSpriteEngine::QQuickSpriteEngine(QList<QQuickSprite*> sprites, QObject *parent) - : QQuickStochasticEngine(parent), m_startedImageAssembly(false), m_loaded(false) + : QQuickSpriteEngine(parent) { foreach (QQuickSprite* sprite, sprites) m_states << (QQuickStochasticState*)sprite; diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index f3254cf8d7..65044d33d4 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -1423,6 +1423,39 @@ QQuickText::~QQuickText() Text { text: "Hello"; font.capitalization: Font.AllLowercase } \endqml */ + +/*! + \qmlproperty enumeration QtQuick::Text::font.hintingPreference + \since 5.8 + + Sets the preferred hinting on the text. This is a hint to the underlying text rendering system + to use a certain level of hinting, and has varying support across platforms. See the table in + the documentation for QFont::HintingPreference for more details. + + \note This property only has an effect when used together with render type Text.NativeRendering. + + \list + \value Font.PreferDefaultHinting - Use the default hinting level for the target platform. + \value Font.PreferNoHinting - If possible, render text without hinting the outlines + of the glyphs. The text layout will be typographically accurate, using the same metrics + as are used e.g. when printing. + \value Font.PreferVerticalHinting - If possible, render text with no horizontal hinting, + but align glyphs to the pixel grid in the vertical direction. The text will appear + crisper on displays where the density is too low to give an accurate rendering + of the glyphs. But since the horizontal metrics of the glyphs are unhinted, the text's + layout will be scalable to higher density devices (such as printers) without impacting + details such as line breaks. + \value Font.PreferFullHinting - If possible, render text with hinting in both horizontal and + vertical directions. The text will be altered to optimize legibility on the target + device, but since the metrics will depend on the target size of the text, the positions + of glyphs, line breaks, and other typographical detail will not scale, meaning that a + text layout may look different on devices with different pixel densities. + \endlist + + \qml + Text { text: "Hello"; renderType: Text.NativeRendering; font.hintingPreference: Font.PreferVerticalHinting } + \endqml +*/ QFont QQuickText::font() const { Q_D(const QQuickText); diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index 0cee9c7d27..45238e2d0c 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -44,6 +44,7 @@ #include <qcoreapplication.h> #include <qfont.h> +#include <qfontmetrics.h> #include <qevent.h> #include <qdebug.h> #include <qdrag.h> @@ -982,6 +983,14 @@ process: { QString text = e->text(); if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) { + if (overwriteMode + // no need to call deleteChar() if we have a selection, insertText + // does it already + && !cursor.hasSelection() + && !cursor.atBlockEnd()) { + cursor.deleteChar(); + } + cursor.insertText(text); selectionChanged(); } else { @@ -1024,6 +1033,12 @@ QRectF QQuickTextControlPrivate::rectForPosition(int position) const if (line.isValid()) { qreal x = line.cursorToX(relativePos); qreal w = 0; + if (overwriteMode) { + if (relativePos < line.textLength() - line.textStart()) + w = line.cursorToX(relativePos + 1) - x; + else + w = QFontMetrics(block.layout()->font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw() + } r = QRectF(layoutPos.x() + x, layoutPos.y() + line.y(), textCursorWidth + w, line.height()); } else { r = QRectF(layoutPos.x(), layoutPos.y(), textCursorWidth, 10); // #### correct height @@ -1506,6 +1521,21 @@ bool QQuickTextControl::hasImState() const return d->hasImState; } +bool QQuickTextControl::overwriteMode() const +{ + Q_D(const QQuickTextControl); + return d->overwriteMode; +} + +void QQuickTextControl::setOverwriteMode(bool overwrite) +{ + Q_D(QQuickTextControl); + if (d->overwriteMode == overwrite) + return; + d->overwriteMode = overwrite; + emit overwriteModeChanged(overwrite); +} + bool QQuickTextControl::cursorVisible() const { Q_D(const QQuickTextControl); diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h index ca5a3d3191..602e457cb8 100644 --- a/src/quick/items/qquicktextcontrol_p.h +++ b/src/quick/items/qquicktextcontrol_p.h @@ -94,6 +94,8 @@ public: #endif bool hasImState() const; + bool overwriteMode() const; + void setOverwriteMode(bool overwrite); bool cursorVisible() const; void setCursorVisible(bool visible); QRectF anchorRect() const; @@ -149,6 +151,7 @@ Q_SIGNALS: void copyAvailable(bool b); void selectionChanged(); void cursorPositionChanged(); + void overwriteModeChanged(bool overwriteMode); // control signals void updateCursorRequest(); diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 5968028c26..36eb5d3cde 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -323,6 +323,39 @@ QString QQuickTextEdit::text() const */ /*! + \qmlproperty enumeration QtQuick::TextEdit::font.hintingPreference + \since 5.8 + + Sets the preferred hinting on the text. This is a hint to the underlying text rendering system + to use a certain level of hinting, and has varying support across platforms. See the table in + the documentation for QFont::HintingPreference for more details. + + \note This property only has an effect when used together with render type TextEdit.NativeRendering. + + \list + \value Font.PreferDefaultHinting - Use the default hinting level for the target platform. + \value Font.PreferNoHinting - If possible, render text without hinting the outlines + of the glyphs. The text layout will be typographically accurate, using the same metrics + as are used e.g. when printing. + \value Font.PreferVerticalHinting - If possible, render text with no horizontal hinting, + but align glyphs to the pixel grid in the vertical direction. The text will appear + crisper on displays where the density is too low to give an accurate rendering + of the glyphs. But since the horizontal metrics of the glyphs are unhinted, the text's + layout will be scalable to higher density devices (such as printers) without impacting + details such as line breaks. + \value Font.PreferFullHinting - If possible, render text with hinting in both horizontal and + vertical directions. The text will be altered to optimize legibility on the target + device, but since the metrics will depend on the target size of the text, the positions + of glyphs, line breaks, and other typographical detail will not scale, meaning that a + text layout may look different on devices with different pixel densities. + \endlist + + \qml + TextEdit { text: "Hello"; renderType: TextEdit.NativeRendering; font.hintingPreference: Font.PreferVerticalHinting } + \endqml +*/ + +/*! \qmlproperty string QtQuick::TextEdit::text The text to display. If the text format is AutoText the text edit will @@ -1583,6 +1616,32 @@ bool QQuickTextEdit::event(QEvent *event) } /*! + \qmlproperty bool QtQuick::TextEdit::overwriteMode + \since 5.8 + Whether text entered by the user will overwrite existing text. + + As with many text editors, the text editor widget can be configured + to insert or overwrite existing text with new text entered by the user. + + If this property is \c true, existing text is overwritten, character-for-character + by new text; otherwise, text is inserted at the cursor position, displacing + existing text. + + By default, this property is \c false (new text does not overwrite existing text). +*/ +bool QQuickTextEdit::overwriteMode() const +{ + Q_D(const QQuickTextEdit); + return d->control->overwriteMode(); +} + +void QQuickTextEdit::setOverwriteMode(bool overwrite) +{ + Q_D(QQuickTextEdit); + d->control->setOverwriteMode(overwrite); +} + +/*! \overload Handles the given key \a event. */ @@ -2193,6 +2252,7 @@ void QQuickTextEditPrivate::init() qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorRectangleChanged()), q, QQuickTextEdit, SLOT(moveCursorDelegate())); qmlobject_connect(control, QQuickTextControl, SIGNAL(linkActivated(QString)), q, QQuickTextEdit, SIGNAL(linkActivated(QString))); qmlobject_connect(control, QQuickTextControl, SIGNAL(linkHovered(QString)), q, QQuickTextEdit, SIGNAL(linkHovered(QString))); + qmlobject_connect(control, QQuickTextControl, SIGNAL(overwriteModeChanged(bool)), q, QQuickTextEdit, SIGNAL(overwriteModeChanged(bool))); qmlobject_connect(control, QQuickTextControl, SIGNAL(textChanged()), q, QQuickTextEdit, SLOT(q_textChanged())); qmlobject_connect(control, QQuickTextControl, SIGNAL(preeditTextChanged()), q, QQuickTextEdit, SIGNAL(preeditTextChanged())); #ifndef QT_NO_CLIPBOARD diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h index f6ecb984e3..42c9064860 100644 --- a/src/quick/items/qquicktextedit_p.h +++ b/src/quick/items/qquicktextedit_p.h @@ -86,6 +86,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged) Q_PROPERTY(QRectF cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged) Q_PROPERTY(QQmlComponent* cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged) + Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode NOTIFY overwriteModeChanged) Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged) Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged) Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged) @@ -199,6 +200,9 @@ public: QQmlComponent* cursorDelegate() const; void setCursorDelegate(QQmlComponent*); + bool overwriteMode() const; + void setOverwriteMode(bool overwrite); + int selectionStart() const; int selectionEnd() const; @@ -313,6 +317,7 @@ Q_SIGNALS: void readOnlyChanged(bool isReadOnly); void cursorVisibleChanged(bool isCursorVisible); void cursorDelegateChanged(); + void overwriteModeChanged(bool overwriteMode); void activeFocusOnPressChanged(bool activeFocusOnPressed); void persistentSelectionChanged(bool isPersistentSelection); void textMarginChanged(qreal textMargin); diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 504dece0d1..9b7eb4ea4b 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -345,6 +345,38 @@ QString QQuickTextInputPrivate::realText() const \endqml */ +/*! + \qmlproperty enumeration QtQuick::TextInput::font.hintingPreference + \since 5.8 + + Sets the preferred hinting on the text. This is a hint to the underlying text rendering system + to use a certain level of hinting, and has varying support across platforms. See the table in + the documentation for QFont::HintingPreference for more details. + + \note This property only has an effect when used together with render type TextInput.NativeRendering. + + \list + \value Font.PreferDefaultHinting - Use the default hinting level for the target platform. + \value Font.PreferNoHinting - If possible, render text without hinting the outlines + of the glyphs. The text layout will be typographically accurate, using the same metrics + as are used e.g. when printing. + \value Font.PreferVerticalHinting - If possible, render text with no horizontal hinting, + but align glyphs to the pixel grid in the vertical direction. The text will appear + crisper on displays where the density is too low to give an accurate rendering + of the glyphs. But since the horizontal metrics of the glyphs are unhinted, the text's + layout will be scalable to higher density devices (such as printers) without impacting + details such as line breaks. + \value Font.PreferFullHinting - If possible, render text with hinting in both horizontal and + vertical directions. The text will be altered to optimize legibility on the target + device, but since the metrics will depend on the target size of the text, the positions + of glyphs, line breaks, and other typographical detail will not scale, meaning that a + text layout may look different on devices with different pixel densities. + \endlist + + \qml + TextInput { text: "Hello"; renderType: TextInput.NativeRendering; font.hintingPreference: Font.PreferVerticalHinting } + \endqml +*/ QFont QQuickTextInput::font() const { Q_D(const QQuickTextInput); @@ -808,7 +840,14 @@ QRectF QQuickTextInput::cursorRectangle() const return QRectF(); qreal x = l.cursorToX(c) - d->hscroll + leftPadding(); qreal y = l.y() - d->vscroll + topPadding(); - return QRectF(x, y, 1, l.height()); + qreal w = 1; + if (d->overwriteMode) { + if (c < text().length()) + w = l.cursorToX(c + 1) - x; + else + w = QFontMetrics(font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw() + } + return QRectF(x, y, w, l.height()); } /*! @@ -1288,7 +1327,14 @@ QRectF QQuickTextInput::positionToRectangle(int pos) const return QRectF(); qreal x = l.cursorToX(pos) - d->hscroll; qreal y = l.y() - d->vscroll; - return QRectF(x, y, 1, l.height()); + qreal w = 1; + if (d->overwriteMode) { + if (pos < text().length()) + w = l.cursorToX(pos + 1) - x; + else + w = QFontMetrics(font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw() + } + return QRectF(x, y, w, l.height()); } /*! @@ -1370,6 +1416,36 @@ int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPositi return line.isValid() ? line.xToCursor(x, position) : 0; } +/*! + \qmlproperty bool QtQuick::TextInput::overwriteMode + \since 5.8 + + Whether text entered by the user will overwrite existing text. + + As with many text editors, the text editor widget can be configured + to insert or overwrite existing text with new text entered by the user. + + If this property is \c true, existing text is overwritten, character-for-character + by new text; otherwise, text is inserted at the cursor position, displacing + existing text. + + By default, this property is \c false (new text does not overwrite existing text). +*/ +bool QQuickTextInput::overwriteMode() const +{ + Q_D(const QQuickTextInput); + return d->overwriteMode; +} + +void QQuickTextInput::setOverwriteMode(bool overwrite) +{ + Q_D(QQuickTextInput); + if (d->overwriteMode == overwrite) + return; + d->overwriteMode = overwrite; + emit overwriteModeChanged(overwrite); +} + void QQuickTextInput::keyPressEvent(QKeyEvent* ev) { Q_D(QQuickTextInput); @@ -2767,7 +2843,7 @@ void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate) // characters) QChar* uc = str.data(); for (int i = 0; i < (int)str.length(); ++i) { - if ((uc[i] < 0x20 && uc[i] != 0x09) + if ((uc[i].unicode() < 0x20 && uc[i] != QChar::Tabulation) || uc[i] == QChar::LineSeparator || uc[i] == QChar::ParagraphSeparator || uc[i] == QChar::ObjectReplacementCharacter) @@ -4448,6 +4524,14 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event) if (unknown && !m_readOnly) { QString t = event->text(); if (!t.isEmpty() && t.at(0).isPrint()) { + if (overwriteMode + // no need to call del() if we have a selection, insert + // does it already + && !hasSelectedText() + && !(m_cursor == q_func()->text().length())) { + del(); + } + insert(t); event->accept(); return; diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h index 211d9146fc..d0461f551e 100644 --- a/src/quick/items/qquicktextinput_p.h +++ b/src/quick/items/qquicktextinput_p.h @@ -79,6 +79,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged) Q_PROPERTY(QRectF cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged) Q_PROPERTY(QQmlComponent *cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged) + Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode NOTIFY overwriteModeChanged) Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged) Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged) Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged) @@ -245,6 +246,9 @@ public: QQmlComponent* cursorDelegate() const; void setCursorDelegate(QQmlComponent*); + bool overwriteMode() const; + void setOverwriteMode(bool overwrite); + bool focusOnPress() const; void setFocusOnPress(bool); @@ -325,6 +329,7 @@ Q_SIGNALS: void readOnlyChanged(bool isReadOnly); void cursorVisibleChanged(bool isCursorVisible); void cursorDelegateChanged(); + void overwriteModeChanged(bool overwriteMode); void maximumLengthChanged(int maximumLength); void validatorChanged(); void inputMaskChanged(const QString &inputMask); diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index 57a9f6413a..93a8778c40 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -158,6 +158,7 @@ public: , m_passwordEchoEditing(false) , inLayout(false) , requireImplicitWidth(false) + , overwriteMode(false) { } @@ -299,6 +300,7 @@ public: bool m_passwordEchoEditing : 1; bool inLayout:1; bool requireImplicitWidth:1; + bool overwriteMode:1; static inline QQuickTextInputPrivate *get(QQuickTextInput *t) { return t->d_func(); diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp index 2872c3e230..7b600adf53 100644 --- a/src/quick/items/qquicktextnodeengine.cpp +++ b/src/quick/items/qquicktextnodeengine.cpp @@ -731,10 +731,13 @@ void QQuickTextNodeEngine::mergeProcessedNodes(QList<BinaryTreeNode *> *regularN QVector<QPointF> glyphPositions = glyphRun.positions(); glyphPositions.reserve(count); + QRectF glyphBoundingRect = glyphRun.boundingRect(); + for (int j = 1; j < nodes.size(); ++j) { BinaryTreeNode *otherNode = nodes.at(j); glyphIndexes += otherNode->glyphRun.glyphIndexes(); primaryNode->ranges += otherNode->ranges; + glyphBoundingRect = glyphBoundingRect.united(otherNode->glyphRun.boundingRect()); QVector<QPointF> otherPositions = otherNode->glyphRun.positions(); for (int k = 0; k < otherPositions.size(); ++k) @@ -746,6 +749,7 @@ void QQuickTextNodeEngine::mergeProcessedNodes(QList<BinaryTreeNode *> *regularN glyphRun.setGlyphIndexes(glyphIndexes); glyphRun.setPositions(glyphPositions); + glyphRun.setBoundingRect(glyphBoundingRect); } } } diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp index 3ce96b673d..1101b88992 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -194,9 +194,8 @@ QQuickView::QQuickView(QWindow *parent) */ QQuickView::QQuickView(const QUrl &source, QWindow *parent) -: QQuickWindow(*(new QQuickViewPrivate), parent) + : QQuickView(parent) { - d_func()->init(); setSource(source); } diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index b06cfe54cc..48e5b54016 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -79,11 +79,12 @@ QT_BEGIN_NAMESPACE -Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch"); -Q_LOGGING_CATEGORY(DBG_TOUCH_TARGET, "qt.quick.touch.target"); -Q_LOGGING_CATEGORY(DBG_MOUSE, "qt.quick.mouse"); -Q_LOGGING_CATEGORY(DBG_FOCUS, "qt.quick.focus"); -Q_LOGGING_CATEGORY(DBG_DIRTY, "qt.quick.dirty"); +Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch") +Q_LOGGING_CATEGORY(DBG_TOUCH_TARGET, "qt.quick.touch.target") +Q_LOGGING_CATEGORY(DBG_MOUSE, "qt.quick.mouse") +Q_LOGGING_CATEGORY(DBG_MOUSE_TARGET, "qt.quick.mouse.target") +Q_LOGGING_CATEGORY(DBG_FOCUS, "qt.quick.focus") +Q_LOGGING_CATEGORY(DBG_DIRTY, "qt.quick.dirty") extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); @@ -746,6 +747,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber) if (mouseGrabberItem == grabber) return; + qCDebug(DBG_MOUSE_TARGET) << "grabber" << mouseGrabberItem << "->" << grabber; QQuickItem *oldGrabber = mouseGrabberItem; mouseGrabberItem = grabber; @@ -1174,10 +1176,8 @@ void QQuickWindowPrivate::cleanup(QSGNode *n) Constructs a window for displaying a QML scene with parent window \a parent. */ QQuickWindow::QQuickWindow(QWindow *parent) - : QWindow(*(new QQuickWindowPrivate), parent) + : QQuickWindow(*new QQuickWindowPrivate, parent) { - Q_D(QQuickWindow); - d->init(this); } @@ -1654,7 +1654,7 @@ void QQuickWindow::mouseReleaseEvent(QMouseEvent *event) return; } - qCDebug(DBG_MOUSE) << "QQuickWindow::mouseReleaseEvent()" << event->localPos() << event->button() << event->buttons(); + qCDebug(DBG_MOUSE) << "QQuickWindow::mouseReleaseEvent()" << event->localPos() << event->button() << event->buttons() << "grabber:" << d->mouseGrabberItem; if (!d->mouseGrabberItem) { QWindow::mouseReleaseEvent(event); @@ -1761,13 +1761,15 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce return false; } - QList<QQuickItem *> children = itemPrivate->paintOrderChildItems(); - for (int ii = children.count() - 1; ii >= 0; --ii) { - QQuickItem *child = children.at(ii); - if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled) - continue; - if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted)) - return true; + if (itemPrivate->hasHoverInChild) { + QList<QQuickItem *> children = itemPrivate->paintOrderChildItems(); + for (int ii = children.count() - 1; ii >= 0; --ii) { + QQuickItem *child = children.at(ii); + if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled) + continue; + if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted)) + return true; + } } if (itemPrivate->hoverEnabled) { @@ -2182,7 +2184,7 @@ bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even return (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty()); } -// touchEventForItemBounds has no means to generate a touch event that contains +// touchEventForItem has no means to generate a touch event that contains // only the points that are relevant for this item. Thus the need for // matchingPoints to already be that set of interesting points. // They are all pre-transformed, too. @@ -2244,7 +2246,7 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv return touchEventAccepted; } -QTouchEvent *QQuickWindowPrivate::touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent) +QTouchEvent *QQuickWindowPrivate::touchEventForItem(QQuickItem *target, const QTouchEvent &originalEvent, bool alwaysCheckBounds) { const QList<QTouchEvent::TouchPoint> &touchPoints = originalEvent.touchPoints(); QList<QTouchEvent::TouchPoint> pointsInBounds; @@ -2252,7 +2254,10 @@ QTouchEvent *QQuickWindowPrivate::touchEventForItemBounds(QQuickItem *target, co if (originalEvent.touchPointStates() != Qt::TouchPointStationary) { for (int i = 0; i < touchPoints.count(); ++i) { const QTouchEvent::TouchPoint &tp = touchPoints.at(i); - if (tp.state() == Qt::TouchPointPressed) { + // Touch presses are relevant to the target item only if they occur inside its bounds. + // Touch updates and releases are relevant if they occur inside, or if we want to + // finish the sequence because the press occurred inside. + if (tp.state() == Qt::TouchPointPressed || alwaysCheckBounds) { QPointF p = target->mapFromScene(tp.scenePos()); if (target->contains(p)) pointsInBounds.append(tp); @@ -2481,7 +2486,7 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target); if (targetPrivate->filtersChildMouseEvents && !hasFiltered->contains(target)) { hasFiltered->insert(target); - QScopedPointer<QTouchEvent> targetEvent(touchEventForItemBounds(target, *event)); + QScopedPointer<QTouchEvent> targetEvent(touchEventForItem(target, *event)); if (!targetEvent->touchPoints().isEmpty()) { if (target->childMouseEventFilter(item, targetEvent.data())) { qCDebug(DBG_TOUCH) << " - first chance intercepted on childMouseEventFilter by " << target; @@ -2561,6 +2566,7 @@ bool QQuickWindowPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem hasFiltered->insert(target); if (target->childMouseEventFilter(item, event)) filtered = true; + qCDebug(DBG_MOUSE_TARGET) << target << "childMouseEventFilter ->" << filtered; } return sendFilteredMouseEvent(target->parentItem(), item, event, hasFiltered) || filtered; @@ -2581,6 +2587,15 @@ bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent return overThreshold; } +bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, const QTouchEvent::TouchPoint *tp, int startDragThreshold) +{ + QStyleHints *styleHints = qApp->styleHints(); + bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance()); + qreal velocity = axis == Qt::XAxis ? tp->velocity().x() : tp->velocity().y(); + overThreshold |= qAbs(velocity) > styleHints->startDragVelocity(); + return overThreshold; +} + /*! \qmlproperty list<Object> Window::data \default diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 1064be7178..1486e20e1e 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -163,8 +163,8 @@ public: void flushDelayedTouchEvent(); bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted); bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints, QSet<QQuickItem*> *filtered); - QTouchEvent *touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent); - QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints); + static QTouchEvent *touchEventForItem(QQuickItem *target, const QTouchEvent &originalEvent, bool alwaysCheckBounds = false); + static QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints); bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event, QSet<QQuickItem*> *filtered); bool sendHoverEvent(QEvent::Type, QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool accepted); @@ -265,6 +265,7 @@ public: static bool defaultAlphaBuffer; static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int startDragThreshold = -1); + static bool dragOverThreshold(qreal d, Qt::Axis axis, const QTouchEvent::TouchPoint *tp, int startDragThreshold = -1); // data property static void data_append(QQmlListProperty<QObject> *, QObject *); |