aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt6
-rw-r--r--src/labs/animation/qquickboundaryrule.cpp4
-rw-r--r--src/particles/qquickimageparticle.cpp7
-rw-r--r--src/particles/qquickimageparticle_p.h2
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvghelpers.cpp1
-rw-r--r--src/qml/doc/src/cmake/qt_add_qml_module.qdoc25
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc69
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc6
-rw-r--r--src/qml/jit/qv4baselinejit.cpp4
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h2
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper.cpp11
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper_p.h1
-rw-r--r--src/qml/jsruntime/qv4engine.cpp6
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp10
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp2
-rw-r--r--src/qml/qml/qqml.cpp7
-rw-r--r--src/qml/qml/qqmlbinding.cpp56
-rw-r--r--src/qml/qml/qqmlengine.cpp15
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp23
-rw-r--r--src/qml/qml/qqmlimport.cpp60
-rw-r--r--src/qml/qml/qqmlmetatype.cpp4
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp24
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp4
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp51
-rw-r--r--src/qml/types/qqmlconnections.cpp14
-rw-r--r--src/qmlcompiler/qqmljslogger_p.h2
-rw-r--r--src/qmldom/qqmldomreformatter.cpp62
-rw-r--r--src/qmlmodels/qqmllistmodel.cpp137
-rw-r--r--src/qmlmodels/qqmllistmodel_p_p.h45
-rw-r--r--src/qmltyperegistrar/qmltypesclassdescription.cpp28
-rw-r--r--src/quick/doc/images/pointerHandlers/tapHandlerButtonReleaseWithinBounds.webpbin0 -> 53154 bytes
-rw-r--r--src/quick/doc/images/pointerHandlers/tapHandlerButtonWithinBounds.webpbin0 -> 27426 bytes
-rw-r--r--src/quick/doc/images/pointerHandlers/tapHandlerOverlappingButtons.webpbin0 -> 51008 bytes
-rw-r--r--src/quick/doc/snippets/pointerHandlers/pointHandler.qml5
-rw-r--r--src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedButtons.qml68
-rw-r--r--src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedModifiers.qml83
-rw-r--r--src/quick/doc/snippets/pointerHandlers/pointHandlerCanvasDrawing.qml101
-rw-r--r--src/quick/doc/snippets/pointerHandlers/pointHandlerMargin.qml83
-rw-r--r--src/quick/doc/snippets/pointerHandlers/tapHandlerButtonReleaseWithinBounds.qml98
-rw-r--r--src/quick/doc/snippets/pointerHandlers/tapHandlerButtonWithinBounds.qml98
-rw-r--r--src/quick/doc/snippets/pointerHandlers/tapHandlerOverlappingButtons.qml98
-rw-r--r--src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc5
-rw-r--r--src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc27
-rw-r--r--src/quick/handlers/qquickdraghandler.cpp10
-rw-r--r--src/quick/handlers/qquickhandlerpoint.cpp25
-rw-r--r--src/quick/handlers/qquickhoverhandler.cpp9
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp12
-rw-r--r--src/quick/handlers/qquickpointerdevicehandler.cpp2
-rw-r--r--src/quick/handlers/qquickpointerhandler.cpp18
-rw-r--r--src/quick/handlers/qquickpointhandler.cpp126
-rw-r--r--src/quick/handlers/qquicksinglepointhandler.cpp2
-rw-r--r--src/quick/handlers/qquicktaphandler.cpp105
-rw-r--r--src/quick/handlers/qquickwheelhandler.cpp2
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp6
-rw-r--r--src/quick/items/qquickflickable.cpp8
-rw-r--r--src/quick/items/qquickflickable_p_p.h1
-rw-r--r--src/quick/items/qquickflipable.cpp54
-rw-r--r--src/quick/items/qquickimage.cpp2
-rw-r--r--src/quick/items/qquickimagebase.cpp4
-rw-r--r--src/quick/items/qquickitem.cpp8
-rw-r--r--src/quick/items/qquickitemsmodule.cpp134
-rw-r--r--src/quick/items/qquickitemview.cpp3
-rw-r--r--src/quick/items/qquicklistview.cpp3
-rw-r--r--src/quick/items/qquickloader.cpp2
-rw-r--r--src/quick/items/qquickrectangle.cpp9
-rw-r--r--src/quick/items/qquickrendercontrol.cpp4
-rw-r--r--src/quick/items/qquickshadereffect.cpp2
-rw-r--r--src/quick/items/qquickspriteengine.cpp1
-rw-r--r--src/quick/items/qquicktableview.cpp35
-rw-r--r--src/quick/items/qquicktableview_p_p.h9
-rw-r--r--src/quick/items/qquicktext.cpp1
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp5
-rw-r--r--src/quick/items/qquickwindow.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.cpp6
-rw-r--r--src/quick/scenegraph/coreapi/qsgtexture.cpp4
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp4
-rw-r--r--src/quick/scenegraph/qsgrhishadereffectnode.cpp12
-rw-r--r--src/quick/util/qquickanimatorjob.cpp5
-rw-r--r--src/quick/util/qquickdeliveryagent.cpp7
-rw-r--r--src/quick/util/qquicktransition.cpp5
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate.qml3
-rw-r--r--src/quickcontrols2/doc/src/includes/container-currentindex.qdocinc9
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickimaginestyle.qdocinc2
-rw-r--r--src/quickcontrols2/imagine/impl/qquickninepatchimage.cpp44
-rw-r--r--src/quickcontrolstestutils/qtest_quickcontrols_p.h4
-rw-r--r--src/quicknativestyle/qstyle/mac/qquickmacstyle_mac.mm2
-rw-r--r--src/quickshapes/qquickshapegenericrenderer.cpp4
-rw-r--r--src/quickshapes/qquickshapesoftwarerenderer.cpp6
-rw-r--r--src/quicktemplates2/qquickdrawer.cpp16
-rw-r--r--src/quicktemplates2/qquickheaderview.cpp2
-rw-r--r--src/quicktemplates2/qquickpopup.cpp2
-rw-r--r--src/quicktemplates2/qquickpopuppositioner.cpp8
-rw-r--r--src/quicktemplates2/qquicksplitview.cpp77
-rw-r--r--src/quicktemplates2/qquickswipeview.cpp2
-rw-r--r--src/quicktemplates2/qquicktabbar.cpp2
-rw-r--r--src/quickwidgets/qquickwidget.cpp19
96 files changed, 1797 insertions, 406 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1f82b16a62..3c6a28072f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -31,7 +31,9 @@ if(TARGET Qt::Gui AND TARGET Qt::qsb AND QT_FEATURE_qml_animation)
find_package(Qt6 ${PROJECT_VERSION} QUIET CONFIG OPTIONAL_COMPONENTS Test)
if(QT_FEATURE_testlib AND TARGET Qt::Test)
add_subdirectory(qmltest)
- add_subdirectory(quicktestutils)
+ if(QT_FEATURE_network)
+ add_subdirectory(quicktestutils)
+ endif()
endif()
if(QT_FEATURE_quick_particles)
@@ -48,7 +50,7 @@ if(TARGET Qt::Gui AND TARGET Qt::qsb AND QT_FEATURE_qml_animation)
add_subdirectory(quickdialogs2)
add_subdirectory(quicknativestyle)
- if(QT_FEATURE_testlib AND TARGET Qt::Test AND TARGET Qt::QuickControls2)
+ if(QT_FEATURE_testlib AND QT_FEATURE_network AND TARGET Qt::Test AND TARGET Qt::QuickControls2)
add_subdirectory(quickcontrolstestutils)
endif()
else()
diff --git a/src/labs/animation/qquickboundaryrule.cpp b/src/labs/animation/qquickboundaryrule.cpp
index 161909b078..0b2d2e2856 100644
--- a/src/labs/animation/qquickboundaryrule.cpp
+++ b/src/labs/animation/qquickboundaryrule.cpp
@@ -146,7 +146,7 @@ void QQuickBoundaryReturnJob::updateState(QAbstractAnimationJob::State newState,
Note that a property cannot have more than one assigned BoundaryRule.
- \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation#Behaviors}{Behavior example}, {Qt QML}
+ \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation#Behaviors}{Behavior example}, {Qt QML}, {Pointer Handlers Example}
*/
QQuickBoundaryRule::QQuickBoundaryRule(QObject *parent)
@@ -419,7 +419,7 @@ bool QQuickBoundaryRule::returnToBounds()
}
/*!
- \qmlproperty qreal QtQuick::BoundaryRule::easing
+ \qmlproperty enumeration QtQuick::BoundaryRule::easing
This property holds the easing curve to be applied in overshoot mode
(whenever the \l minimum or \l maximum constraint is violated, while
diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp
index 884edc3390..750c0446c8 100644
--- a/src/particles/qquickimageparticle.cpp
+++ b/src/particles/qquickimageparticle.cpp
@@ -766,6 +766,7 @@ void QQuickImageParticle::sceneGraphInvalidated()
m_material = nullptr;
delete m_outgoingNode;
m_outgoingNode = nullptr;
+ m_apiChecked = false;
}
void QQuickImageParticle::setImage(const QUrl &image)
@@ -1074,6 +1075,12 @@ void QQuickImageParticle::reset()
update();
}
+
+void QQuickImageParticle::invalidateSceneGraph()
+{
+ reset();
+}
+
void QQuickImageParticle::createEngine()
{
if (m_spriteEngine)
diff --git a/src/particles/qquickimageparticle_p.h b/src/particles/qquickimageparticle_p.h
index 19000f6c9b..03a96b7901 100644
--- a/src/particles/qquickimageparticle_p.h
+++ b/src/particles/qquickimageparticle_p.h
@@ -395,6 +395,8 @@ private Q_SLOTS:
void spritesUpdate(qreal time = 0 );
void mainThreadFetchImageData();
void finishBuildParticleNodes(QSGNode **n);
+ void invalidateSceneGraph();
+
private:
struct ImageData {
QUrl source;
diff --git a/src/plugins/scenegraph/openvg/qsgopenvghelpers.cpp b/src/plugins/scenegraph/openvg/qsgopenvghelpers.cpp
index ab5cfb48b8..615d6e8726 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvghelpers.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvghelpers.cpp
@@ -420,6 +420,7 @@ QImage::Format qVGImageFormatToQImageFormat(VGImageFormat format)
break;
case VG_sL_8:
qImageFormat = QImage::Format_Grayscale8;
+ break;
default:
qImageFormat = QImage::Format_ARGB32;
break;
diff --git a/src/qml/doc/src/cmake/qt_add_qml_module.qdoc b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
index a66aa27561..b81a0c80ea 100644
--- a/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
+++ b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
@@ -59,6 +59,7 @@ qt_add_qml_module(
[RESOURCES ...]
[OUTPUT_TARGETS out_targets_var]
[DESIGNER_SUPPORTED]
+ [NO_PLUGIN]
[NO_PLUGIN_OPTIONAL]
[NO_CREATE_PLUGIN_TARGET]
[NO_GENERATE_PLUGIN_SOURCE]
@@ -324,8 +325,12 @@ been created. When \c NO_CREATE_PLUGIN_TARGET is given, \c PLUGIN_TARGET must
also be provided to explicitly name the plugin target.
Every QML module must define a \c URI. It should be specified in dotted URI
-notation, such as \c{QtQuick.Layouts}. It must not contain anything other than
-alphanumeric or dot characters. Other QML modules may use this name in
+notation, such as \c{QtQuick.Layouts}. Each segment must be a well-formed
+ECMAScript Identifier Name. This means, for example, the segments
+must not start with a number and they must not contain \e{-} (minus)
+characters. As the \c URI will be translated into directory names, you
+should restrict it to alphanumeric characters of the latin alphabet,
+underscores, and dots. Other QML modules may use this name in
\l{qtqml-syntax-imports.html}{import statements} to import the module. The
\c URI will be used in the \c module line of the generated
\l{Module Definition qmldir Files}{qmldir} file. The \c URI is also used to
@@ -412,7 +417,21 @@ plugin class, the \c NO_GENERATE_PLUGIN_SOURCE option should be given. Where no
\c CLASS_NAME is provided, it defaults to the \c URI with dots replaced by
underscores, then \c Plugin appended. Unless the QML module has no plugin, the
class name will be recorded as a \c classname line in the generated
-\l{Module Definition qmldir Files}{qmldir} file.
+\l{Module Definition qmldir Files}{qmldir} file. You need to add any C++ files
+with custom plugin code to the plugin target. Since the plugin then likely
+contains functionality that goes beyond simply loading the backing library, you
+will probably want to add \l{NO_PLUGIN_OPTIONAL}, too. Otherwise the QML engine
+may skip loading the plugin if it detects that the backing library is already
+linked.
+
+\target NO_PLUGIN
+If the \c NO_PLUGIN keyword is given, then no plugin will be built. This
+keyword is thus incompatible with all the options that customize the plugin
+target, in particular \l{NO_GENERATE_PLUGIN_SOURCE}, \l{NO_PLUGIN_OPTIONAL},
+\l{PLUGIN_TARGET}, \l{NO_CREATE_PLUGIN_TARGET}, and \l{CLASS_NAME}. If you do
+not provide a plugin for your module, it will only be fully usable if its
+backing library has been linked into the executable. It is generally hard to
+guarantee that a linker preserves the linkage to a library it considers unused.
\target NO_PLUGIN_OPTIONAL
If the \c NO_PLUGIN_OPTIONAL keyword is given, then the plugin is recorded in
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 40e0627e6d..d4fe08e37d 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -97,15 +97,18 @@ Types to QML} explains, the properties, methods and signals of any
QObject-derived class are accessible from QML code.
To register a QObject-derived class as an instantiable QML object type, add
-\c QML_ELEMENT or \c QML_NAMED_ELEMENT(<name>) to the class declaration and
+\c QML_ELEMENT or \c QML_NAMED_ELEMENT(<name>) to the class declaration. You
+also need to make adjustments in the build system. For qmake, add
\c {CONFIG += qmltypes}, a \c {QML_IMPORT_NAME}, and a
-\c QML_IMPORT_MAJOR_VERSION to your project file. This will register the class
-into the type namespace under the given major version, using either the class
-name or an explicitly given name as QML type name. The minor version(s) will
-be derived from any revisions attached to properties, methods, or signals. The
-default minor version is \c 0. You can explicitly restrict the type to be
-available only from specific minor versions by adding the
-\c QML_ADDED_IN_MINOR_VERSION() macro to the class declaration. Clients can
+\c QML_IMPORT_MAJOR_VERSION to your project file. For CMake, the file containing
+the class should be part of a target set-up with
+\l{qt_add_qml_module}{qt_add_qml_module()}.
+This will register the class into the type namespace under the given major version,
+using either the class name or an explicitly given name as QML type name. The
+minor version(s) will be derived from any revisions attached to properties,
+methods, or signals. The default minor version is \c 0. You can explicitly
+restrict the type to be available only from specific minor versions by adding
+the \c QML_ADDED_IN_MINOR_VERSION() macro to the class declaration. Clients can
import suitable versions of the namespace in order to use the type.
For example, suppose there is a \c Message class with \c author and
@@ -127,26 +130,52 @@ This type can be registered by adding an appropriate type namespace and version
number to the project file. For example, to make the type available in the
\c com.mycompany.messaging namespace with version 1.0:
-\code
-CONFIG += qmltypes
-QML_IMPORT_NAME = com.mycompany.messaging
-QML_IMPORT_MAJOR_VERSION = 1
-\endcode
+\if defined(onlinedocs)
+ \tab {build-qt-app}{tab-cmake}{CMake}{selected}
+ \tab {build-qt-app}{tab-qmake}{qmake}{}
+ \tabcontent {tab-cmake}
+ \else
+ \section3 Using CMake
+\endif
+ \badcode
+ qt_add_qml_module(messaging
+ URI com.mycompany.messaging
+ VERSION 1.0
+ SOURCES
+ message.cpp message.h
+ )
+ \endcode
+\if defined(onlinedocs)
+ \endtabcontent
+ \tabcontent {tab-qmake}
+\else
+ \section3 Using QMake
+\endif
+ \code
+ CONFIG += qmltypes
+ QML_IMPORT_NAME = com.mycompany.messaging
+ QML_IMPORT_MAJOR_VERSION = 1
+ \endcode
+
+ If the header the class is declared in is not accessible from your project's
+ include path, you may have to amend the include path so that the generated
+ registration code can be compiled.
+
+ \code
+ INCLUDEPATH += com/mycompany/messaging
+ \endcode
+\if defined(onlinedocs)
+ \endtabcontent
+\endif
-If the header the class is declared in is not accessible from your project's
-include path, you may have to amend the include path so that the generated
-registration code can be compiled:
-\code
-INCLUDEPATH += com/mycompany/messaging
-\endcode
The type can be used in an \l{qtqml-syntax-basics.html#object-declarations}
{object declaration} from QML, and its properties can be read and written to,
as per the example below:
\qml
-import com.mycompany.messaging 1.0
+import com.mycompany.messaging
Message {
author: "Amelie"
diff --git a/src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc b/src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc
index 7054378b07..493b031b60 100644
--- a/src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc
+++ b/src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc
@@ -44,6 +44,12 @@ Identified modules must be installed into the
\l{qtqml-syntax-imports.html#qml-import-path}{import path} in order to be found
by the QML engine.
+Syntactically, each dot-separated segment of the URI must be a well-formed
+ECMAScript Identifier Name. This means, for example, the segments must not start
+with a number and they must not contain \e{-} (minus) characters. As the URI
+will be translated into directory names, you should restrict it to alphanumeric
+characters of the latin alphabet, underscores, and dots.
+
\section1 Locally Installed Identified Modules
A directory of QML and/or C++ files can be shared as an identified module if it
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index b21acf93c7..ced4c3e057 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -554,6 +554,8 @@ void BaselineJIT::generate_ThrowException()
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(ThrowException, CallResultDestination::Ignore);
as->gotoCatchException();
+
+ // LOAD_ACC(); <- not needed here since it would be unreachable.
}
void BaselineJIT::generate_GetException() { as->getException(); }
@@ -561,9 +563,11 @@ void BaselineJIT::generate_SetException() { as->setException(); }
void BaselineJIT::generate_CreateCallContext()
{
+ STORE_ACC();
as->prepareCallWithArgCount(1);
as->passCppFrameAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(PushCallContext, CallResultDestination::Ignore);
+ LOAD_ACC();
}
void BaselineJIT::generate_PushCatchContext(int index, int name) { as->pushCatchContext(index, name); }
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
index 1873c41261..4000deaeab 100644
--- a/src/qml/jsruntime/qv4arraybuffer_p.h
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -72,7 +72,7 @@ struct Q_QML_PRIVATE_EXPORT SharedArrayBuffer : Object {
void init(size_t length);
void init(const QByteArray& array);
void destroy();
- std::aligned_storage_t<sizeof(QArrayDataPointer<char>), alignof(QArrayDataPointer<char>)> d;
+ struct { alignas(QArrayDataPointer<char>) unsigned char data[sizeof(QArrayDataPointer<char>)]; } d;
const QArrayDataPointer<char> &data() const { return *reinterpret_cast<const QArrayDataPointer<char> *>(&d); }
QArrayDataPointer<char> &data() { return *reinterpret_cast<QArrayDataPointer<char> *>(&d); }
bool isShared;
diff --git a/src/qml/jsruntime/qv4compilationunitmapper.cpp b/src/qml/jsruntime/qv4compilationunitmapper.cpp
index f3e2b445d1..6cff8d3c9b 100644
--- a/src/qml/jsruntime/qv4compilationunitmapper.cpp
+++ b/src/qml/jsruntime/qv4compilationunitmapper.cpp
@@ -65,6 +65,11 @@ public:
s_staticUnits.insert(file, staticUnit);
}
+ void remove(const QString &file)
+ {
+ s_staticUnits.remove(file);
+ }
+
private:
QMutexLocker<QMutex> m_lock;
@@ -105,4 +110,10 @@ CompiledData::Unit *CompilationUnitMapper::get(
return data;
}
+void CompilationUnitMapper::invalidate(const QString &cacheFilePath)
+{
+ StaticUnitCache cache;
+ cache.remove(cacheFilePath);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4compilationunitmapper_p.h b/src/qml/jsruntime/qv4compilationunitmapper_p.h
index 10ad0a6ede..c6773fdd0e 100644
--- a/src/qml/jsruntime/qv4compilationunitmapper_p.h
+++ b/src/qml/jsruntime/qv4compilationunitmapper_p.h
@@ -69,6 +69,7 @@ public:
CompiledData::Unit *get(
const QString &cacheFilePath, const QDateTime &sourceTimeStamp, QString *errorString);
+ static void invalidate(const QString &cacheFilePath);
private:
CompiledData::Unit *open(
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index f47ce4f825..c047298aba 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1530,6 +1530,12 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, QMet
if (typeHint == QMetaType::Bool)
return QVariant(value.toBoolean());
+ if (typeHint == QMetaType::Double)
+ return QVariant(value.toNumber());
+
+ if (typeHint == QMetaType::Float)
+ return QVariant(float(value.toNumber()));
+
if (typeHint == QMetaType::QJsonValue)
return QVariant::fromValue(QV4::JsonObject::toJsonValue(value));
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index bac5104fde..7fe3862172 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -857,8 +857,14 @@ bool ExecutableCompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorSt
return CompiledData::SaveableUnitPointer(unitData()).saveToDisk<char>(
[&unitUrl, errorString](const char *data, quint32 size) {
- return CompiledData::SaveableUnitPointer::writeDataToFile(localCacheFilePath(unitUrl), data,
- size, errorString);
+ const QString cachePath = localCacheFilePath(unitUrl);
+ if (CompiledData::SaveableUnitPointer::writeDataToFile(
+ cachePath, data, size, errorString)) {
+ CompilationUnitMapper::invalidate(cachePath);
+ return true;
+ }
+
+ return false;
});
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index c897c63024..8be952571a 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1992,7 +1992,7 @@ bool CallArgument::fromValue(QMetaType metaType, QV4::ExecutionEngine *engine, c
qvariantPtr->convert(callMetaType);
} else {
QQmlMetaObject mo = ep ? ep->rawMetaObjectForType(callType) : QQmlMetaObject();
- if (!mo.isNull()) {
+ if (!mo.isNull() && v.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
QObject *obj = QQmlMetaType::toQObject(v);
if (obj != nullptr && !QQmlMetaObject::canConvert(obj, mo)) {
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index fddb97e087..1b737ee308 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -1488,7 +1488,12 @@ void AOTCompiledContext::initGetEnumLookup(
{
Q_ASSERT(!engine->hasError());
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- Q_ASSERT(metaObject);
+ if (!metaObject) {
+ engine->handle()->throwTypeError(
+ QStringLiteral("Cannot read property '%1' of undefined")
+ .arg(QString::fromUtf8(enumValue)));
+ return;
+ }
const int enumIndex = metaObject->indexOfEnumerator(enumerator);
const int value = metaObject->enumerator(enumIndex).keyToValue(enumValue);
l->qmlEnumValueLookup.encodedEnumValue = value;
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 3dabaca09f..0b5081d491 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -691,14 +691,34 @@ bool QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const
valueType ? valueType->coreIndex() : -1);
}
-bool QQmlBinding::setTarget(QObject *object, int coreIndex, bool coreIsAlias, int valueTypeIndex)
+static const QQmlPropertyData *getObjectPropertyData(QObject *object, int coreIndex)
{
- m_target = object;
+ QQmlData *data = QQmlData::get(object, true);
+ if (!data)
+ return nullptr;
+ if (!data->propertyCache) {
+ data->propertyCache = QQmlMetaType::propertyCache(object->metaObject());
+ if (!data->propertyCache)
+ return nullptr;
+ data->propertyCache->addref();
+ }
+ const QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
+ Q_ASSERT(propertyData);
+ return propertyData;
+}
- if (!object) {
+bool QQmlBinding::setTarget(QObject *object, int coreIndex, bool coreIsAlias, int valueTypeIndex)
+{
+ auto invalidate = [this]() {
+ m_target = nullptr;
m_targetIndex = QQmlPropertyIndex();
return false;
- }
+ };
+
+ if (!object)
+ return invalidate();
+
+ m_target = object;
for (bool isAlias = coreIsAlias; isAlias;) {
QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
@@ -706,21 +726,25 @@ bool QQmlBinding::setTarget(QObject *object, int coreIndex, bool coreIsAlias, in
int aValueTypeIndex;
if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) {
// can't resolve id (yet)
- m_target = nullptr;
- m_targetIndex = QQmlPropertyIndex();
- return false;
+ return invalidate();
}
- if (valueTypeIndex == -1)
- valueTypeIndex = aValueTypeIndex;
- QQmlData *data = QQmlData::get(object, false);
- if (!data || !data->propertyCache) {
- m_target = nullptr;
- m_targetIndex = QQmlPropertyIndex();
- return false;
+ const QQmlPropertyData *propertyData = getObjectPropertyData(object, coreIndex);
+ if (!propertyData)
+ return invalidate();
+ if (aValueTypeIndex != -1) {
+ if (propertyData->propType().flags().testFlag(QMetaType::PointerToQObject)) {
+ // deep alias
+ propertyData->readProperty(object, &object);
+ coreIndex = aValueTypeIndex;
+ valueTypeIndex = -1;
+ propertyData = getObjectPropertyData(object, coreIndex);
+ if (!propertyData)
+ return invalidate();
+ } else {
+ valueTypeIndex = aValueTypeIndex;
+ }
}
- QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
- Q_ASSERT(propertyData);
m_target = object;
isAlias = propertyData->isAlias();
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 3a2f678419..ff8e2de238 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -1769,7 +1769,7 @@ void QQmlEnginePrivate::cleanupScarceResources()
The newly added \a path will be first in the importPathList().
- \sa setImportPathList(), {QML Modules}
+ \sa setImportPathList(), {QML Modules}, {QML Import Path}
*/
void QQmlEngine::addImportPath(const QString& path)
{
@@ -1787,9 +1787,8 @@ void QQmlEngine::addImportPath(const QString& path)
provided by that module. A \c qmldir file is required for defining the
type version mapping and possibly QML extensions plugins.
- By default, the list contains the directory of the application executable,
- paths specified in the \c QML_IMPORT_PATH environment variable,
- and the builtin \c QmlImportsPath from QLibraryInfo.
+ By default, this list contains the paths mentioned in
+ \l {QML Import Path}.
\sa addImportPath(), setImportPathList()
*/
@@ -1803,9 +1802,11 @@ QStringList QQmlEngine::importPathList() const
Sets \a paths as the list of directories where the engine searches for
installed modules in a URL-based directory structure.
- By default, the list contains the directory of the application executable,
- paths specified in the \c QML_IMPORT_PATH environment variable,
- and the builtin \c QmlImportsPath from QLibraryInfo.
+ By default, this list contains the paths mentioned in
+ \l {QML Import Path}.
+
+ \warning Calling setImportPathList does not preserve the default
+ import paths.
\sa importPathList(), addImportPath()
*/
diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
index 22846a84dc..c2fc291d48 100644
--- a/src/qml/qml/qqmlextensionplugin.cpp
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -43,6 +43,21 @@
QT_BEGIN_NAMESPACE
/*!
+ \since 5.0
+ \inmodule QtQml
+ \class QQmlExtensionPlugin
+ \brief The QQmlExtensionPlugin class provides an abstract base for custom QML extension plugins
+ with custom type registration functions.
+
+ \ingroup plugins
+
+ \note If you need to write a plugin manually (which is rare) you should always use
+ \l{QQmlEngineExtensionPlugin}. QQmlExtensionPlugin only provides the registerTypes() and
+ unregisterTypes() functions in addition. You should not use them, but rather declare your
+ types with \l{QML_ELEMENT} and friends and have the build system take care of the registration.
+*/
+
+/*!
\since 5.14
\inmodule QtQml
\class QQmlEngineExtensionPlugin
@@ -61,7 +76,6 @@ QT_BEGIN_NAMESPACE
/*!
\fn void QQmlExtensionPlugin::registerTypes(const char *uri)
- \internal
Registers the QML types in the given \a uri. Subclasses should implement
this to call qmlRegisterType() for all types which are provided by the extension
@@ -127,9 +141,10 @@ void QQmlExtensionPlugin::unregisterTypes()
}
/*!
- \internal
-*/
-
+ Initializes the extension from the \a uri using the \a engine. Here an application
+ plugin might, for example, expose some data or objects to QML,
+ as context properties on the engine's root context.
+ */
void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
{
Q_UNUSED(engine);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index e35df5b907..d04d6751cd 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1169,6 +1169,26 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
return stableRelativePath;
}
+/* removes all file selector occurrences in path
+ firstPlus is the position of the initial '+' in the path
+ which we always have as we check for '+' to decide whether
+ we need to do some work at all
+*/
+static QString pathWithoutFileSelectors(QString path, // we want a copy of path
+ qsizetype firstPlus)
+{
+ do {
+ Q_ASSERT(path.at(firstPlus) == u'+');
+ const auto eos = path.size();
+ qsizetype terminatingSlashPos = firstPlus + 1;
+ while (terminatingSlashPos != eos && path.at(terminatingSlashPos) != u'/')
+ ++terminatingSlashPos;
+ path.remove(firstPlus, terminatingSlashPos - firstPlus + 1);
+ firstPlus = path.indexOf(u'+', firstPlus);
+ } while (firstPlus != -1);
+ return path;
+}
+
/*!
\internal
@@ -1215,10 +1235,42 @@ QTypeRevision QQmlImportsPrivate::matchingQmldirVersion(
typedef QQmlDirComponents::const_iterator ConstIterator;
const QQmlDirComponents &components = qmldir.components();
+ QMultiHash<QString, ConstIterator> baseFileName2ConflictingComponents;
+
ConstIterator cend = components.constEnd();
for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) {
for (ConstIterator cit2 = components.constBegin(); cit2 != cit; ++cit2) {
if (cit2->typeName == cit->typeName && cit2->version == cit->version) {
+ // ugly heuristic to deal with file selectors
+ const auto comp2PotentialFileSelectorPos = cit2->fileName.indexOf(u'+');
+ const bool comp2MightHaveFileSelector = comp2PotentialFileSelectorPos != -1;
+ /* If we detect conflicting paths, we check if they agree when we remove anything looking like a
+ file selector.
+ We need to create copies of the filenames, otherwise QString::replace would modify the
+ existing file-names
+ */
+ QString compFileName1 = cit->fileName;
+ QString compFileName2 = cit2->fileName;
+ if (auto fileSelectorPos1 = compFileName1.indexOf(u'+'); fileSelectorPos1 != -1) {
+ // existing entry was file selector entry, fix it up
+ // it could also be the case that _both_ are using file selectors
+ QString baseName = comp2MightHaveFileSelector ? pathWithoutFileSelectors(compFileName2,
+ comp2PotentialFileSelectorPos)
+ : compFileName2;
+ if (pathWithoutFileSelectors(compFileName1, fileSelectorPos1) == baseName) {
+ baseFileName2ConflictingComponents.insert(baseName, cit);
+ baseFileName2ConflictingComponents.insert(baseName, cit2);
+ continue;
+ }
+ // fall through to error case
+ } else if (comp2MightHaveFileSelector) {
+ // new entry contains file selector (and we now that cit did not)
+ if (pathWithoutFileSelectors(compFileName2, comp2PotentialFileSelectorPos) == compFileName1) {
+ baseFileName2ConflictingComponents.insert(compFileName1, cit2);
+ continue;
+ }
+ // fall through to error case
+ }
// This entry clashes with a predecessor
QQmlError error;
error.setDescription(QQmlImportDatabase::tr("\"%1\" version %2.%3 is defined more than once in module \"%4\"")
@@ -1232,6 +1284,14 @@ QTypeRevision QQmlImportsPrivate::matchingQmldirVersion(
addVersion(cit->version);
}
+ // ensure that all components point to the actual base URL, and let the file selectors resolve them correctly during URL resolution
+ for (auto keyIt = baseFileName2ConflictingComponents.keyBegin(); keyIt != baseFileName2ConflictingComponents.keyEnd(); ++keyIt) {
+ const QString& baseFileName = *keyIt;
+ const auto conflictingComponents = baseFileName2ConflictingComponents.values(baseFileName);
+ for (ConstIterator component: conflictingComponents)
+ component->fileName = baseFileName;
+ }
+
typedef QList<QQmlDirParser::Script>::const_iterator SConstIterator;
const QQmlDirScripts &scripts = qmldir.scripts();
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index a61cf4adea..fdf74f4873 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -337,6 +337,10 @@ void QQmlMetaType::clearTypeRegistrations()
data->urlToNonFileImportType.clear();
data->metaObjectToType.clear();
data->undeletableTypes.clear();
+
+ for (auto it = data->propertyCaches.begin(), end = data->propertyCaches.end(); it != end; ++it)
+ (*it)->release();
+ data->propertyCaches.clear();
}
int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &function)
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 69b0755e2d..0a96bb0af8 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -1475,16 +1475,24 @@ bool QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
void *argv[] = { &bindable };
// allow interception
target->metaObject()->metacall(target, QMetaObject::BindableProperty, index, argv);
- bindable.setBinding(qmlBinding);
+ const bool success = bindable.setBinding(qmlBinding);
+
+ // Only pop_front after setting the binding as the bindings are refcounted.
sharedState->allQPropertyBindings.pop_front();
- if (auto priv = QPropertyBindingPrivate::get(qmlBinding); priv->hasCustomVTable()) {
- auto qmlBindingPriv = static_cast<QQmlPropertyBinding *>(priv);
- auto jsExpression = qmlBindingPriv->jsExpression();
- const bool canRemove = !qmlBinding.error().hasError() && !qmlBindingPriv->hasDependencies()
- && !jsExpression->hasUnresolvedNames();
- if (canRemove)
- bindable.takeBinding();
+
+ // If the binding was actually not set, it's deleted now.
+ if (success) {
+ if (auto priv = QPropertyBindingPrivate::get(qmlBinding); priv->hasCustomVTable()) {
+ auto qmlBindingPriv = static_cast<QQmlPropertyBinding *>(priv);
+ auto jsExpression = qmlBindingPriv->jsExpression();
+ const bool canRemove = !qmlBinding.error().hasError()
+ && !qmlBindingPriv->hasDependencies()
+ && !jsExpression->hasUnresolvedNames();
+ if (canRemove)
+ bindable.takeBinding();
+ }
}
+
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
return false;
}
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index b03b8e937a..2ebba1eb72 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -51,8 +51,8 @@
#include <QtCore/qdebug.h>
#include <QtCore/QCryptographicHash>
+#include <QtCore/private/qtools_p.h>
-#include <ctype.h> // for toupper
#include <limits.h>
#include <algorithm>
@@ -527,7 +527,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
QVarLengthArray<char, 128> str(length+3);
str[0] = 'o';
str[1] = 'n';
- str[2] = toupper(rawName[0]);
+ str[2] = QtMiscUtils::toAsciiUpper(rawName[0]);
if (length > 1)
memcpy(&str[3], &rawName[1], length - 1);
str[length + 2] = '\0';
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 837199904e..46dc108b9e 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -375,26 +375,10 @@ QVariant QtObject::quaternion(double scalar, double x, double y, double z) const
}
/*!
- \qmlmethod matrix4x4 Qt::matrix4x4(real m11, real m12, real m13, real m14, real m21, real m22, real m23, real m24, real m31, real m32, real m33, real m34, real m41, real m42, real m43, real m44)
-
- Returns a matrix4x4 with the specified values.
-
- The arguments correspond to their positions in the matrix:
-
- \table
- \row \li \a m11 \li \a m12 \li \a m13 \li \a m14
- \row \li \a m21 \li \a m22 \li \a m23 \li \a m24
- \row \li \a m31 \li \a m32 \li \a m33 \li \a m34
- \row \li \a m41 \li \a m42 \li \a m43 \li \a m44
- \endtable
+ \qmlmethod matrix4x4 Qt::matrix4x4()
- Alternatively, the function may be called with a single argument
- where that argument is a JavaScript array which contains the sixteen
- matrix values.
-
- Finally, the function may be called with no arguments and the resulting
- matrix will be the identity matrix.
-*/
+ Returns an identity matrix4x4.
+ */
QVariant QtObject::matrix4x4() const
{
QVariant variant;
@@ -402,6 +386,21 @@ QVariant QtObject::matrix4x4() const
return variant;
}
+/*!
+ \qmlmethod matrix4x4 Qt::matrix4x4(var values)
+
+ Returns a matrix4x4 with the specified \a values. \a values is expected to
+ be a JavaScript array with 16 entries.
+
+ The array indices correspond to positions in the matrix as follows:
+
+ \table
+ \row \li 0 \li 1 \li 2 \li 3
+ \row \li 4 \li 5 \li 6 \li 7
+ \row \li 8 \li 9 \li 10 \li 11
+ \row \li 12 \li 13 \li 14 \li 15
+ \endtable
+*/
QVariant QtObject::matrix4x4(const QJSValue &value) const
{
if (value.isObject()) {
@@ -415,6 +414,20 @@ QVariant QtObject::matrix4x4(const QJSValue &value) const
return QVariant();
}
+/*!
+ \qmlmethod matrix4x4 Qt::matrix4x4(real m11, real m12, real m13, real m14, real m21, real m22, real m23, real m24, real m31, real m32, real m33, real m34, real m41, real m42, real m43, real m44)
+
+ Returns a matrix4x4 with the specified values.
+
+ The arguments correspond to their positions in the matrix:
+
+ \table
+ \row \li \a m11 \li \a m12 \li \a m13 \li \a m14
+ \row \li \a m21 \li \a m22 \li \a m23 \li \a m24
+ \row \li \a m31 \li \a m32 \li \a m33 \li \a m34
+ \row \li \a m41 \li \a m42 \li \a m43 \li \a m44
+ \endtable
+*/
QVariant QtObject::matrix4x4(double m11, double m12, double m13, double m14,
double m21, double m22, double m23, double m24,
double m31, double m32, double m33, double m34,
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index f13a39946d..70e048b0ea 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -60,15 +60,13 @@ Q_LOGGING_CATEGORY(lcQmlConnections, "qt.qml.connections")
class QQmlConnectionsPrivate : public QObjectPrivate
{
public:
- QQmlConnectionsPrivate() : target(nullptr), enabled(true), targetSet(false), ignoreUnknownSignals(false), componentcomplete(true) {}
-
QList<QQmlBoundSignal*> boundsignals;
- QObject *target;
+ QQmlGuard<QObject> target;
- bool enabled;
- bool targetSet;
- bool ignoreUnknownSignals;
- bool componentcomplete;
+ bool enabled = true;
+ bool targetSet = false;
+ bool ignoreUnknownSignals = false;
+ bool componentcomplete = true;
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
QList<const QV4::CompiledData::Binding *> bindings;
@@ -159,7 +157,7 @@ QQmlConnections::~QQmlConnections()
QObject *QQmlConnections::target() const
{
Q_D(const QQmlConnections);
- return d->targetSet ? d->target : parent();
+ return d->targetSet ? d->target.data() : parent();
}
class QQmlBoundSignalDeleter : public QObject
diff --git a/src/qmlcompiler/qqmljslogger_p.h b/src/qmlcompiler/qqmljslogger_p.h
index 5ccbe91045..2d63a860c3 100644
--- a/src/qmlcompiler/qqmljslogger_p.h
+++ b/src/qmlcompiler/qqmljslogger_p.h
@@ -63,7 +63,7 @@ public:
\param location: The location where an error occurred.
*/
IssueLocationWithContext(QStringView code, const QQmlJS::SourceLocation &location) {
- int before = qMax(0,code.lastIndexOf(QLatin1Char('\n'), location.offset));
+ quint32 before = qMax(0, code.lastIndexOf(QLatin1Char('\n'), location.offset));
if (before != 0) before++;
diff --git a/src/qmldom/qqmldomreformatter.cpp b/src/qmldom/qqmldomreformatter.cpp
index d627af12ef..ee48a71c29 100644
--- a/src/qmldom/qqmldomreformatter.cpp
+++ b/src/qmldom/qqmldomreformatter.cpp
@@ -972,7 +972,11 @@ protected:
// to check
bool visit(TypeExpression *) override { return true; }
- bool visit(SuperLiteral *) override { return true; }
+ bool visit(SuperLiteral *) override
+ {
+ out("super");
+ return true;
+ }
bool visit(PatternProperty *) override { return true; }
bool visit(ComputedPropertyName *) override
{
@@ -989,7 +993,61 @@ protected:
}
bool visit(YieldExpression *) override { return true; }
bool visit(ClassExpression *) override { return true; }
- bool visit(ClassDeclaration *) override { return true; }
+
+ // Return false because we want to omit default function calls in accept0 implementation.
+ bool visit(ClassDeclaration *ast) override
+ {
+ preVisit(ast);
+ out(ast->classToken);
+ out(" ");
+ out(ast->name);
+ if (ast->heritage) {
+ out(" extends ");
+ accept(ast->heritage);
+ }
+ out(" {");
+ int baseIndent = lw.increaseIndent();
+ for (ClassElementList *it = ast->elements; it; it = it->next) {
+ PatternProperty *property = it->property;
+ lw.newline();
+ preVisit(property);
+ if (it->isStatic)
+ out("static ");
+ if (property->type == PatternProperty::Getter)
+ out("get ");
+ else if (property->type == PatternProperty::Setter)
+ out("set ");
+ FunctionExpression *f = AST::cast<FunctionExpression *>(property->initializer);
+ const bool scoped = f->lbraceToken.length != 0;
+ out(f->functionToken);
+ out(f->lparenToken);
+ accept(f->formals);
+ out(f->rparenToken);
+ out(f->lbraceToken);
+ if (scoped)
+ ++expressionDepth;
+ if (f->body) {
+ if (f->body->next || scoped) {
+ lnAcceptIndented(f->body);
+ lw.newline();
+ } else {
+ baseIndent = lw.increaseIndent(1);
+ accept(f->body);
+ lw.decreaseIndent(1, baseIndent);
+ }
+ }
+ if (scoped)
+ --expressionDepth;
+ out(f->rbraceToken);
+ lw.newline();
+ postVisit(property);
+ }
+ lw.decreaseIndent(1, baseIndent);
+ out("}");
+ postVisit(ast);
+ return false;
+ }
+
bool visit(ClassElementList *) override { return true; }
bool visit(Program *) override { return true; }
bool visit(NameSpaceImport *) override { return true; }
diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp
index 039098a80e..c060aaec97 100644
--- a/src/qmlmodels/qqmllistmodel.cpp
+++ b/src/qmlmodels/qqmllistmodel.cpp
@@ -129,8 +129,28 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(QV4::String *key, Role::Data
const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::Role::DataType type)
{
- const int dataSizes[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(ListElement::GuardedQObjectPointer), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QUrl), sizeof(QJSValue) };
- const int dataAlignments[] = { alignof(StringOrTranslation), alignof(double), alignof(bool), alignof(ListModel *), alignof(QObject *), alignof(QVariantMap), alignof(QDateTime), alignof(QUrl), alignof(QJSValue) };
+ const int dataSizes[] = {
+ sizeof(StringOrTranslation),
+ sizeof(double),
+ sizeof(bool),
+ sizeof(ListModel *),
+ sizeof(QV4::PersistentValue),
+ sizeof(QVariantMap),
+ sizeof(QDateTime),
+ sizeof(QUrl),
+ sizeof(QJSValue)
+ };
+ const int dataAlignments[] = {
+ alignof(StringOrTranslation),
+ alignof(double),
+ alignof(bool),
+ alignof(ListModel *),
+ alignof(QV4::PersistentValue),
+ alignof(QVariantMap),
+ alignof(QDateTime),
+ alignof(QUrl),
+ alignof(QJSValue)
+ };
Role *r = new Role;
r->name = key;
@@ -634,10 +654,9 @@ void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles)
roleIndex = e->setFunctionProperty(r, jsv);
} else if (QV4::Object *o = propertyValue->as<QV4::Object>()) {
if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) {
- QObject *o = wrapper->object();
const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
if (role.type == ListLayout::Role::QObject)
- roleIndex = e->setQObjectProperty(role, o);
+ roleIndex = e->setQObjectProperty(role, wrapper);
} else if (QVariant maybeUrl = o->engine()->toVariant(o->asReturnedValue(), QMetaType::fromType<QUrl>(), true);
maybeUrl.metaType() == QMetaType::fromType<QUrl>()) {
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Url);
@@ -725,10 +744,9 @@ void ListModel::set(int elementIndex, QV4::Object *object, ListModel::SetElement
}
} else if (QV4::Object *o = propertyValue->as<QV4::Object>()) {
if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) {
- QObject *o = wrapper->object();
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
if (r.type == ListLayout::Role::QObject)
- e->setQObjectPropertyFast(r, o);
+ e->setQObjectPropertyFast(r, wrapper);
} else {
QVariant maybeUrl = o->engine()->toVariant(o->asReturnedValue(), QMetaType::fromType<QUrl>(), true);
if (maybeUrl.metaType() == QMetaType::fromType<QUrl>()) {
@@ -852,12 +870,11 @@ StringOrTranslation *ListElement::getStringProperty(const ListLayout::Role &role
return s;
}
-QObject *ListElement::getQObjectProperty(const ListLayout::Role &role)
+QV4::QObjectWrapper *ListElement::getQObjectProperty(const ListLayout::Role &role)
{
char *mem = getPropertyMemory(role);
- GuardedQObjectPointer *o
- = reinterpret_cast<GuardedQObjectPointer *>(mem);
- return o->data();
+ QV4::PersistentValue *g = reinterpret_cast<QV4::PersistentValue *>(mem);
+ return g->as<QV4::QObjectWrapper>();
}
QVariantMap *ListElement::getVariantMapProperty(const ListLayout::Role &role)
@@ -904,13 +921,13 @@ QJSValue *ListElement::getFunctionProperty(const ListLayout::Role &role)
return f;
}
-ListElement::GuardedQObjectPointer *
+QV4::PersistentValue *
ListElement::getGuardProperty(const ListLayout::Role &role)
{
char *mem = getPropertyMemory(role);
bool existingGuard = false;
- for (size_t i = 0; i < sizeof(GuardedQObjectPointer);
+ for (size_t i = 0; i < sizeof(QV4::PersistentValue);
++i) {
if (mem[i] != 0) {
existingGuard = true;
@@ -918,12 +935,12 @@ ListElement::getGuardProperty(const ListLayout::Role &role)
}
}
- GuardedQObjectPointer *o = nullptr;
+ QV4::PersistentValue *g = nullptr;
if (existingGuard)
- o = reinterpret_cast<GuardedQObjectPointer *>(mem);
+ g = reinterpret_cast<QV4::PersistentValue *>(mem);
- return o;
+ return g;
}
ListModel *ListElement::getListProperty(const ListLayout::Role &role)
@@ -979,12 +996,8 @@ QVariant ListElement::getProperty(const ListLayout::Role &role, const QQmlListMo
break;
case ListLayout::Role::QObject:
{
- GuardedQObjectPointer *guard =
- reinterpret_cast<GuardedQObjectPointer *>(
- mem);
- QObject *object = guard->data();
- if (object)
- data = QVariant::fromValue(object);
+ QV4::PersistentValue *guard = reinterpret_cast<QV4::PersistentValue *>(mem);
+ data = QVariant::fromValue(guard->as<QV4::QObjectWrapper>()->object());
}
break;
case ListLayout::Role::VariantMap:
@@ -1096,67 +1109,17 @@ int ListElement::setListProperty(const ListLayout::Role &role, ListModel *m)
return roleIndex;
}
-static void
-restoreQObjectOwnership(ListElement::GuardedQObjectPointer *pointer)
-{
- if (QObject *o = pointer->data()) {
- QQmlData *data = QQmlData::get(o, false);
- Q_ASSERT(data);
-
- // Only restore the previous state if the object hasn't become explicitly
- // owned
- if (!data->explicitIndestructibleSet)
- data->indestructible = (pointer->tag() & ListElement::Indestructible);
- }
-}
-
-static void setQObjectOwnership(char *mem, QObject *o)
-{
- QQmlData *ddata = QQmlData::get(o, false);
- const int ownership = (!ddata || ddata->indestructible ? ListElement::Indestructible : 0)
- | (ddata && ddata->explicitIndestructibleSet ? ListElement::ExplicitlySet : 0);
-
- // If ddata didn't exist above, force its creation now
- if (!ddata)
- ddata = QQmlData::get(o, true);
-
- if (!ddata->explicitIndestructibleSet)
- ddata->indestructible = ownership != 0;
-
- new (mem) ListElement::GuardedQObjectPointer(
- o, static_cast<ListElement::ObjectIndestructible>(ownership));
-}
-
-int ListElement::setQObjectProperty(const ListLayout::Role &role, QObject *o)
+int ListElement::setQObjectProperty(const ListLayout::Role &role, QV4::QObjectWrapper *o)
{
int roleIndex = -1;
if (role.type == ListLayout::Role::QObject) {
char *mem = getPropertyMemory(role);
- GuardedQObjectPointer *g =
- reinterpret_cast<GuardedQObjectPointer *>(mem);
- bool existingGuard = false;
- for (size_t i = 0; i < sizeof(GuardedQObjectPointer);
- ++i) {
- if (mem[i] != 0) {
- existingGuard = true;
- break;
- }
- }
- bool changed;
- if (existingGuard) {
- changed = g->data() != o;
- if (changed)
- restoreQObjectOwnership(g);
- g->~GuardedQObjectPointer();
- } else {
- changed = true;
- }
-
- setQObjectOwnership(mem, o);
-
- if (changed)
- roleIndex = role.index;
+ if (isMemoryUsed<QVariantMap>(mem))
+ reinterpret_cast<QV4::PersistentValue *>(mem)->set(o->engine(), *o);
+ else
+ new (mem) QV4::PersistentValue(o->engine(), o);
+ roleIndex = role.index;
}
return roleIndex;
@@ -1289,11 +1252,10 @@ void ListElement::setBoolPropertyFast(const ListLayout::Role &role, bool b)
*value = b;
}
-void ListElement::setQObjectPropertyFast(const ListLayout::Role &role, QObject *o)
+void ListElement::setQObjectPropertyFast(const ListLayout::Role &role, QV4::QObjectWrapper *o)
{
char *mem = getPropertyMemory(role);
-
- setQObjectOwnership(mem, o);
+ new (mem) QV4::PersistentValue(o->engine(), o);
}
void ListElement::setListPropertyFast(const ListLayout::Role &role, ListModel *m)
@@ -1410,7 +1372,7 @@ QVector<int> ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElem
break;
case ListLayout::Role::QObject:
{
- QObject *object = src->getQObjectProperty(srcRole);
+ QV4::QObjectWrapper *object = src->getQObjectProperty(srcRole);
roleIndex = target->setQObjectProperty(targetRole, object);
}
break;
@@ -1465,14 +1427,8 @@ void ListElement::destroy(ListLayout *layout)
break;
case ListLayout::Role::QObject:
{
- GuardedQObjectPointer *guard =
- getGuardProperty(r);
-
- if (guard) {
- restoreQObjectOwnership(guard);
-
- guard->~GuardedQObjectPointer();
- }
+ if (QV4::PersistentValue *guard = getGuardProperty(r))
+ guard->~PersistentValue();
}
break;
case ListLayout::Role::VariantMap:
@@ -1609,8 +1565,7 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d
QV4::ScopedObject o(scope, d);
QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>();
if (role.type == ListLayout::Role::QObject && wrapper) {
- QObject *o = wrapper->object();
- roleIndex = setQObjectProperty(role, o);
+ roleIndex = setQObjectProperty(role, wrapper);
} else if (role.type == ListLayout::Role::VariantMap) {
roleIndex = setVariantMapProperty(role, o);
} else if (role.type == ListLayout::Role::Url) {
diff --git a/src/qmlmodels/qqmllistmodel_p_p.h b/src/qmlmodels/qqmllistmodel_p_p.h
index 2ec7ea04db..19cba980f4 100644
--- a/src/qmlmodels/qqmllistmodel_p_p.h
+++ b/src/qmlmodels/qqmllistmodel_p_p.h
@@ -281,43 +281,6 @@ public:
enum ObjectIndestructible { Indestructible = 1, ExplicitlySet = 2 };
enum { BLOCK_SIZE = 64 - sizeof(int) - sizeof(ListElement *) - sizeof(ModelNodeMetaObject *) };
- // This is a basic guarded QObject pointer, with tag. It cannot be copied or moved.
- class GuardedQObjectPointer
- {
- Q_DISABLE_COPY_MOVE(GuardedQObjectPointer)
-
- using RefCountData = QtSharedPointer::ExternalRefCountData;
- using Storage = QTaggedPointer<QObject, ObjectIndestructible>;
-
- public:
- GuardedQObjectPointer(QObject *o, ObjectIndestructible ownership)
- : storage(o, ownership)
- , refCount(o ? RefCountData::getAndRef(o) : nullptr)
- {}
-
- ~GuardedQObjectPointer()
- {
- if (refCount && !refCount->weakref.deref())
- delete refCount;
- }
-
- QObject *data() const
- {
- return (refCount == nullptr || refCount->strongref.loadRelaxed() == 0)
- ? nullptr
- : storage.data();
- }
-
- ObjectIndestructible tag() const
- {
- return storage.tag();
- }
-
- private:
- Storage storage;
- RefCountData *refCount = nullptr;
- };
-
ListElement();
ListElement(int existingUid);
~ListElement();
@@ -336,7 +299,7 @@ private:
int setDoubleProperty(const ListLayout::Role &role, double n);
int setBoolProperty(const ListLayout::Role &role, bool b);
int setListProperty(const ListLayout::Role &role, ListModel *m);
- int setQObjectProperty(const ListLayout::Role &role, QObject *o);
+ int setQObjectProperty(const ListLayout::Role &role, QV4::QObjectWrapper *o);
int setVariantMapProperty(const ListLayout::Role &role, QV4::Object *o);
int setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m);
int setDateTimeProperty(const ListLayout::Role &role, const QDateTime &dt);
@@ -347,7 +310,7 @@ private:
void setStringPropertyFast(const ListLayout::Role &role, const QString &s);
void setDoublePropertyFast(const ListLayout::Role &role, double n);
void setBoolPropertyFast(const ListLayout::Role &role, bool b);
- void setQObjectPropertyFast(const ListLayout::Role &role, QObject *o);
+ void setQObjectPropertyFast(const ListLayout::Role &role, QV4::QObjectWrapper *o);
void setListPropertyFast(const ListLayout::Role &role, ListModel *m);
void setVariantMapFast(const ListLayout::Role &role, QV4::Object *o);
void setDateTimePropertyFast(const ListLayout::Role &role, const QDateTime &dt);
@@ -359,8 +322,8 @@ private:
QVariant getProperty(const ListLayout::Role &role, const QQmlListModel *owner, QV4::ExecutionEngine *eng);
ListModel *getListProperty(const ListLayout::Role &role);
StringOrTranslation *getStringProperty(const ListLayout::Role &role);
- QObject *getQObjectProperty(const ListLayout::Role &role);
- GuardedQObjectPointer *getGuardProperty(const ListLayout::Role &role);
+ QV4::QObjectWrapper *getQObjectProperty(const ListLayout::Role &role);
+ QV4::PersistentValue *getGuardProperty(const ListLayout::Role &role);
QVariantMap *getVariantMapProperty(const ListLayout::Role &role);
QDateTime *getDateTimeProperty(const ListLayout::Role &role);
QUrl *getUrlProperty(const ListLayout::Role &role);
diff --git a/src/qmltyperegistrar/qmltypesclassdescription.cpp b/src/qmltyperegistrar/qmltypesclassdescription.cpp
index bf6c0ca5ed..b58d4ac00a 100644
--- a/src/qmltyperegistrar/qmltypesclassdescription.cpp
+++ b/src/qmltyperegistrar/qmltypesclassdescription.cpp
@@ -261,11 +261,29 @@ void QmlTypesClassDescription::collect(
accessSemantics = QLatin1String("reference");
} else {
isCreatable = false;
- // If no classDef, we assume it's a value type defined by the foreign/extended trick.
- // Objects and namespaces always have metaobjects and therefore classDefs.
- accessSemantics = (!classDef || classDef->value(QLatin1String("gadget")).toBool())
- ? QLatin1String("value")
- : QLatin1String("none");
+
+ if (!classDef) {
+ if (elementName.isEmpty() || elementName[0].isLower()) {
+ // If no classDef, we generally assume it's a value type defined by the
+ // foreign/extended trick.
+ accessSemantics = QLatin1String("value");
+ } else {
+ // Objects and namespaces always have metaobjects and therefore classDefs.
+ // However, we may not be able to resolve the metaobject at compile time. See
+ // the "Invisible" test case. In that case, we must not assume anything about
+ // access semantics.
+ qWarning() << "Warning: Refusing to generate non-lowercase name"
+ << elementName << "for unknown foreign type";
+ elementName.clear();
+ // Make it completely inaccessible.
+ // We cannot get enums from anonymous types after all.
+ accessSemantics = QLatin1String("none");
+ }
+ } else if (classDef->value(QLatin1String("gadget")).toBool()) {
+ accessSemantics = QLatin1String("value");
+ } else {
+ accessSemantics = QLatin1String("none");
+ }
}
}
diff --git a/src/quick/doc/images/pointerHandlers/tapHandlerButtonReleaseWithinBounds.webp b/src/quick/doc/images/pointerHandlers/tapHandlerButtonReleaseWithinBounds.webp
new file mode 100644
index 0000000000..3edab7d7a1
--- /dev/null
+++ b/src/quick/doc/images/pointerHandlers/tapHandlerButtonReleaseWithinBounds.webp
Binary files differ
diff --git a/src/quick/doc/images/pointerHandlers/tapHandlerButtonWithinBounds.webp b/src/quick/doc/images/pointerHandlers/tapHandlerButtonWithinBounds.webp
new file mode 100644
index 0000000000..05cb2f2276
--- /dev/null
+++ b/src/quick/doc/images/pointerHandlers/tapHandlerButtonWithinBounds.webp
Binary files differ
diff --git a/src/quick/doc/images/pointerHandlers/tapHandlerOverlappingButtons.webp b/src/quick/doc/images/pointerHandlers/tapHandlerOverlappingButtons.webp
new file mode 100644
index 0000000000..0455097159
--- /dev/null
+++ b/src/quick/doc/images/pointerHandlers/tapHandlerOverlappingButtons.webp
Binary files differ
diff --git a/src/quick/doc/snippets/pointerHandlers/pointHandler.qml b/src/quick/doc/snippets/pointerHandlers/pointHandler.qml
index 20be120120..138ad332d9 100644
--- a/src/quick/doc/snippets/pointerHandlers/pointHandler.qml
+++ b/src/quick/doc/snippets/pointerHandlers/pointHandler.qml
@@ -48,8 +48,7 @@
**
****************************************************************************/
//![0]
-import QtQuick 2.12
-import QtQuick.Window 2.2
+import QtQuick
Window {
width: 480
@@ -61,6 +60,7 @@ Window {
z: 10000
anchors.fill: parent
+ //![1]
PointHandler {
id: handler
acceptedDevices: PointerDevice.TouchScreen | PointerDevice.TouchPad
@@ -73,6 +73,7 @@ Window {
width: 20; height: width; radius: width / 2
}
}
+ //![1]
}
}
//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedButtons.qml b/src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedButtons.qml
new file mode 100644
index 0000000000..a884672b0d
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedButtons.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Item {
+ width: 480; height: 320
+
+ Rectangle {
+ color: handler.active ? "tomato" : "wheat"
+ x: handler.point.position.x - width / 2
+ y: handler.point.position.y - height / 2
+ width: 20; height: width; radius: width / 2
+ }
+
+ PointHandler {
+ id: handler
+ acceptedButtons: Qt.MiddleButton | Qt.RightButton
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedModifiers.qml b/src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedModifiers.qml
new file mode 100644
index 0000000000..0229f3bb0a
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedModifiers.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Item {
+ id: feedbackPane
+ width: 480; height: 320
+
+ PointHandler {
+ id: control
+ acceptedModifiers: Qt.ControlModifier
+ cursorShape: Qt.PointingHandCursor
+ target: Rectangle {
+ parent: feedbackPane
+ color: control.active ? "indianred" : "khaki"
+ x: control.point.position.x - width / 2
+ y: control.point.position.y - height / 2
+ width: 20; height: width; radius: width / 2
+ }
+ }
+
+ PointHandler {
+ id: shift
+ acceptedModifiers: Qt.ShiftModifier | Qt.MetaModifier
+ cursorShape: Qt.CrossCursor
+ target: Rectangle {
+ parent: feedbackPane
+ color: shift.active ? "darkslateblue" : "lightseagreen"
+ x: shift.point.position.x - width / 2
+ y: shift.point.position.y - height / 2
+ width: 30; height: width; radius: width / 2
+ }
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/pointHandlerCanvasDrawing.qml b/src/quick/doc/snippets/pointerHandlers/pointHandlerCanvasDrawing.qml
new file mode 100644
index 0000000000..5bc98c1230
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/pointHandlerCanvasDrawing.qml
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//![0]
+import QtQuick
+
+Canvas {
+ id: canvas
+ width: 800
+ height: 600
+ antialiasing: true
+ renderTarget: Canvas.FramebufferObject
+ property var points: []
+ onPaint: {
+ if (points.length < 2)
+ return
+ var ctx = canvas.getContext('2d');
+ ctx.save()
+ ctx.strokeStyle = stylusHandler.active ? "blue" : "white"
+ ctx.lineCap = "round"
+ ctx.beginPath()
+ ctx.moveTo(points[0].x, points[0].y)
+ for (var i = 1; i < points.length; i++)
+ ctx.lineTo(points[i].x, points[i].y)
+ ctx.lineWidth = 3
+ ctx.stroke()
+ points = points.slice(points.length - 2, 1)
+ ctx.restore()
+ }
+
+ PointHandler {
+ id: stylusHandler
+ acceptedPointerTypes: PointerDevice.Pen
+ onPointChanged: {
+ canvas.points.push(point.position)
+ canvas.requestPaint()
+ }
+ }
+
+ PointHandler {
+ id: eraserHandler
+ acceptedPointerTypes: PointerDevice.Eraser
+ onPointChanged: {
+ canvas.points.push(point.position)
+ canvas.requestPaint()
+ }
+ }
+
+ Rectangle {
+ width: 10; height: 10
+ color: stylusHandler.active ? "green" : eraserHandler.active ? "red" : "beige"
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/pointHandlerMargin.qml b/src/quick/doc/snippets/pointerHandlers/pointHandlerMargin.qml
new file mode 100644
index 0000000000..49161f0abe
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/pointHandlerMargin.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Item {
+ width: 480; height: 320
+
+ Rectangle {
+ anchors.fill: handlingContainer
+ anchors.margins: -handler.margin
+ color: "beige"
+ }
+
+ Rectangle {
+ id: handlingContainer
+ width: 200; height: 200
+ anchors.centerIn: parent
+ border.color: "green"
+ color: handler.active ? "lightsteelblue" : "khaki"
+
+ Text {
+ text: "X"
+ x: handler.point.position.x - width / 2
+ y: handler.point.position.y - height / 2
+ visible: handler.active
+ }
+
+ PointHandler {
+ id: handler
+ margin: 30
+ }
+ }
+
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/tapHandlerButtonReleaseWithinBounds.qml b/src/quick/doc/snippets/pointerHandlers/tapHandlerButtonReleaseWithinBounds.qml
new file mode 100644
index 0000000000..a6b1673d4c
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/tapHandlerButtonReleaseWithinBounds.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Item {
+ width: 120; height: 80
+
+ component Button : Rectangle {
+ id: button
+ signal clicked
+ property alias text: buttonLabel.text
+
+ width: 80
+ height: 40
+ radius: 3
+ property color dark: Qt.darker(palette.button, 1.3)
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: tapHandler.pressed ? dark : palette.button }
+ GradientStop { position: 1.0; color: dark }
+ }
+
+ SequentialAnimation on border.width {
+ id: tapFlash
+ running: false
+ loops: 3
+ PropertyAction { value: 2 }
+ PauseAnimation { duration: 100 }
+ PropertyAction { value: 0 }
+ PauseAnimation { duration: 100 }
+ }
+
+ //![1]
+ TapHandler {
+ id: tapHandler
+ gesturePolicy: TapHandler.ReleaseWithinBounds
+ onTapped: tapFlash.start()
+ }
+ //![1]
+
+ Text {
+ id: buttonLabel
+ text: "Click Me"
+ color: palette.buttonText
+ anchors.centerIn: parent
+ }
+ }
+
+ Button { x: 10; y: 10 }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/tapHandlerButtonWithinBounds.qml b/src/quick/doc/snippets/pointerHandlers/tapHandlerButtonWithinBounds.qml
new file mode 100644
index 0000000000..f2e968599c
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/tapHandlerButtonWithinBounds.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Item {
+ width: 120; height: 80
+
+ component Button : Rectangle {
+ id: button
+ signal clicked
+ property alias text: buttonLabel.text
+
+ width: 80
+ height: 40
+ radius: 3
+ property color dark: Qt.darker(palette.button, 1.3)
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: tapHandler.pressed ? dark : palette.button }
+ GradientStop { position: 1.0; color: dark }
+ }
+
+ SequentialAnimation on border.width {
+ id: tapFlash
+ running: false
+ loops: 3
+ PropertyAction { value: 2 }
+ PauseAnimation { duration: 100 }
+ PropertyAction { value: 0 }
+ PauseAnimation { duration: 100 }
+ }
+
+ //![1]
+ TapHandler {
+ id: tapHandler
+ gesturePolicy: TapHandler.WithinBounds
+ onTapped: tapFlash.start()
+ }
+ //![1]
+
+ Text {
+ id: buttonLabel
+ text: "Click Me"
+ color: palette.buttonText
+ anchors.centerIn: parent
+ }
+ }
+
+ Button { x: 10; y: 10 }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/tapHandlerOverlappingButtons.qml b/src/quick/doc/snippets/pointerHandlers/tapHandlerOverlappingButtons.qml
new file mode 100644
index 0000000000..993330a5ec
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/tapHandlerOverlappingButtons.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Item {
+ width: 120; height: 80
+
+ component Button : Rectangle {
+ signal clicked
+ property alias text: buttonLabel.text
+
+ width: 80
+ height: 40
+ radius: 3
+ property color dark: Qt.darker(palette.button, 1.3)
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: tapHandler.pressed ? dark : palette.button }
+ GradientStop { position: 1.0; color: dark }
+ }
+
+ SequentialAnimation on border.width {
+ id: tapFlash
+ running: false
+ loops: 3
+ PropertyAction { value: 2 }
+ PauseAnimation { duration: 100 }
+ PropertyAction { value: 0 }
+ PauseAnimation { duration: 100 }
+ }
+
+ //![1]
+ TapHandler {
+ id: tapHandler
+ gesturePolicy: TapHandler.DragThreshold // the default
+ onTapped: tapFlash.start()
+ }
+ //![1]
+
+ Text {
+ id: buttonLabel
+ text: "Click Me"
+ color: palette.buttonText
+ anchors.centerIn: parent
+ }
+ }
+
+ Button { x: 10; y: 10 }
+ Button { x: 30; y: 30 }
+}
+//![0]
diff --git a/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc b/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc
index bf889a9066..7a05583a82 100644
--- a/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc
+++ b/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc
@@ -41,6 +41,8 @@
behavioral concerns are better separated, and the behavior is built up by
finer-grained composition.
+ The \l {Pointer Handlers Example} demonstrates some use cases for these.
+
The pre-existing \l Keys attached property is similar in concept, so we
refer to the pointing-device-oriented handlers plus \c Keys together as the
set of Input Handlers. We expect to offer more attached-property use cases
@@ -94,7 +96,8 @@
PointHandler) can work only with passive grabs; others require exclusive
grabs; and others can "lurk" with passive grabs until they detect that a
gesture is being performed, and then make the transition from passive to
- exclusive grab.
+ exclusive grab. TapHandler's grabbing behavior is
+ \l {TapHandler::gesturePolicy}{configurable}.
When a grab transition is requested, \l PointerHandler::grabPermissions,
\l QQuickItem::keepMouseGrab() and \l QQuickItem::keepTouchGrab() control
diff --git a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
index 30c940e6ea..9aa404a612 100644
--- a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
+++ b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
@@ -52,11 +52,16 @@ options that align with the latest UI design trends. If these UI controls do not
satisfy your application's needs, only then it is recommended to create a
custom control.
+You can use the controls when you design UIs in Qt Design Studio. In addition,
+it provides timeline-based animations, visual effects, layouts, and a
+live-preview for prototyping applications.
\section2 Related Information
\list
\li \l{Qt Quick Controls}
+\li \l{Customizing Qt Quick Controls}
\li \l{Qt Quick}
+\li \l{Qt Design Studio Manual}
\endlist
\omit
@@ -117,7 +122,7 @@ All QML files listed under \c {QML_FILES} will automatically get compiled \l {Ah
\li \l{The Qt Resource System}
\endlist
-\section1 Separate UI from Logic
+\section1 Separate UI from Business Logic
One of the key goals that most application developers want to achieve is to
create a maintainable application. One of the ways to achieve this goal is
@@ -133,8 +138,8 @@ reasons why an application's UI should be written in QML:
\li JavaScript can easily be used in QML to respond to events.
\endlist
-Being a strongly typed language, C++ is best suited for an application's logic.
-Typically, such code performs tasks such as complex calculations
+Being a strongly typed language, C++ is best suited for an application's
+business logic. Typically, such code performs tasks such as complex calculations
or data processing, which are faster in C++ than QML.
Qt offers various approaches to integrate QML and C++ code in an application.
@@ -177,6 +182,22 @@ see \l {Choosing the Correct Integration Method Between C++ and QML}.
\li \l{Qt Quick Controls - Chat Tutorial}{Chat application tutorial}
\endlist
+\section1 Using Qt Design Studio
+
+Qt Design Studio uses UI files that have the filename extension \e {.ui.qml}
+to separate the visual parts of the UI from the UI logic you implement in
+\e {.qml} files. You should edit UI files only in the \uicontrol {2D} view in
+Qt Design Studio. If you use some other tool to add code that Qt Design Studio
+does not support, it displays error messages. Fix the errors to enable visual
+editing of the UI files again. Typically, you should move the unsupported code
+to a \e {.qml} file.
+
+\section2 Related Information
+
+\list
+ \li \l{Qt Design Studio: UI Files}
+\endlist
+
\section1 Using Qt Quick Layouts
Qt offers Qt Quick Layouts to arrange Qt Quick items visually in a layout.
diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp
index f150c7e6ac..8c9464ee55 100644
--- a/src/quick/handlers/qquickdraghandler.cpp
+++ b/src/quick/handlers/qquickdraghandler.cpp
@@ -88,7 +88,7 @@ Q_LOGGING_CATEGORY(lcDragHandler, "qt.quick.handler.drag")
At this time, drag-and-drop is not yet supported.
- \sa Drag, MouseArea
+ \sa Drag, MouseArea, {Pointer Handlers Example}
*/
QQuickDragHandler::QQuickDragHandler(QQuickItem *parent)
@@ -131,13 +131,13 @@ void QQuickDragHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDe
This property holds the snap mode.
- The snap mode configures snapping of the \l target item's center to the event point.
+ The snap mode configures snapping of the \l target item's center to the \l eventPoint.
Possible values:
\value DragHandler.SnapNever Never snap
- \value DragHandler.SnapAuto The \l target snaps if the event point was pressed outside of the \l target
- item \e and the \l target is a descendant of \l parentItem (default)
- \value DragHandler.SnapWhenPressedOutsideTarget The \l target snaps if the event point was pressed outside of the \l target
+ \value DragHandler.SnapAuto The \l target snaps if the \l eventPoint was pressed outside of the \l target
+ item \e and the \l target is a descendant of \l {PointerHandler::}{parent} item (default)
+ \value DragHandler.SnapWhenPressedOutsideTarget The \l target snaps if the \l eventPoint was pressed outside of the \l target
\value DragHandler.SnapAlways Always snap
*/
QQuickDragHandler::SnapMode QQuickDragHandler::snapMode() const
diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp
index 65cc3d4937..52513f8273 100644
--- a/src/quick/handlers/qquickhandlerpoint.cpp
+++ b/src/quick/handlers/qquickhandlerpoint.cpp
@@ -49,7 +49,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcTouchTarget)
\inqmlmodule QtQuick
\brief An event point.
- A QML representation of a QEventPoint.
+ A handler-owned QML representation of a QEventPoint.
It's possible to make bindings to properties of a handler's current
\l {SinglePointHandler::point}{point} or
@@ -58,12 +58,12 @@ Q_DECLARE_LOGGING_CATEGORY(lcTouchTarget)
\snippet pointerHandlers/dragHandlerNullTarget.qml 0
The point is kept up-to-date when the DragHandler is actively responding to
- an EventPoint; but after the point is released, or when the current point is
+ an \l eventPoint; but after the point is released, or when the current point is
being handled by a different handler, \c position.x and \c position.y are 0.
- \note This is practically identical to QtQuick::EventPoint; however an
- EventPoint is a long-lived QObject which is invalidated between gestures
- and reused for subsequent event deliveries. Continuous bindings to its
+ \note This is practically identical to \l eventPoint; however an eventPoint
+ is a short-lived copy of a long-lived Q_GADGET which is invalidated between
+ gestures and reused for subsequent event deliveries. Continuous bindings to its
properties are not possible, and an individual handler cannot rely on it
outside the period when that point is part of an active gesture which that
handler is handling. HandlerPoint is a Q_GADGET that the handler owns.
@@ -186,7 +186,7 @@ void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points)
During a touch gesture, from the time that the first finger is pressed
until the last finger is released, each touchpoint will have a unique ID
number. Likewise, if input from multiple devices occurs (for example
- simultaneous mouse and touch presses), all the current event points from
+ simultaneous mouse and touch presses), all the current \l{eventPoint}{eventPoints} from
all the devices will have unique IDs.
\note Do not assume that id numbers start at zero or that they are
@@ -223,7 +223,7 @@ void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points)
\qmlproperty QPointF QtQuick::HandlerPoint::position
\brief The position within the \c parent Item
- This is the position of the event point relative to the bounds of
+ This is the position of the \l eventPoint relative to the bounds of
the \l {PointerHandler::parent} {parent}.
*/
@@ -232,7 +232,7 @@ void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points)
\qmlproperty QPointF QtQuick::HandlerPoint::scenePosition
\brief The position within the scene
- This is the position of the event point relative to the bounds of the Qt
+ This is the position of the \l eventPoint relative to the bounds of the Qt
Quick scene (typically the whole window).
*/
@@ -290,7 +290,7 @@ void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points)
This is a velocity vector pointing in the direction of movement, in logical
pixels per second. It has x and y components, at least one of which will be
nonzero when this point is in motion. It holds the average recent velocity:
- how fast and in which direction the event point has been moving recently.
+ how fast and in which direction the \l eventPoint has been moving recently.
\sa QtQuick::TouchPoint::velocity, QEventPoint::velocity
*/
@@ -345,6 +345,13 @@ void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points)
\sa QtQuick::TouchPoint::ellipseDiameters, QEventPoint::ellipseDiameters
*/
+/*!
+ \readonly
+ \qmlproperty PointerDevice QtQuick::handlerPoint::device
+
+ This property holds the device that the point (and its event) came from.
+*/
+
QT_END_NAMESPACE
#include "moc_qquickhandlerpoint_p.cpp"
diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp
index 6e2b25a605..c5067881a6 100644
--- a/src/quick/handlers/qquickhoverhandler.cpp
+++ b/src/quick/handlers/qquickhoverhandler.cpp
@@ -67,7 +67,7 @@ Q_LOGGING_CATEGORY(lcHoverHandler, "qt.quick.handler.hover")
The \l cursorShape property allows changing the cursor whenever
\l hovered changes to \c true.
- \sa MouseArea, PointHandler
+ \sa MouseArea, PointHandler, {Pointer Handlers Example}
*/
QQuickHoverHandler::QQuickHoverHandler(QQuickItem *parent)
@@ -302,6 +302,13 @@ void QQuickHoverHandler::setHovered(bool hovered)
\sa Qt::CursorShape, QQuickItem::cursor()
*/
+/*!
+ \internal
+ \qmlproperty flags HoverHandler::dragThreshold
+
+ This property is not used in HoverHandler.
+*/
+
QT_END_NAMESPACE
#include "moc_qquickhoverhandler_p.cpp"
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
index c2d7df30fc..cb45509de0 100644
--- a/src/quick/handlers/qquickpinchhandler.cpp
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -92,7 +92,7 @@ Q_LOGGING_CATEGORY(lcPinchHandler, "qt.quick.handler.pinch")
but if it's a disallowed number, it does not scale or rotate
its \l target, and the \l active property remains \c false.
- \sa PinchArea, QPointerEvent::pointCount(), QNativeGestureEvent::fingerCount()
+ \sa PinchArea, QPointerEvent::pointCount(), QNativeGestureEvent::fingerCount(), {Pointer Handlers Example}
*/
QQuickPinchHandler::QQuickPinchHandler(QQuickItem *parent)
@@ -462,6 +462,13 @@ void QQuickPinchHandler::handlePointerEventImpl(QPointerEvent *event)
}
/*!
+ \internal
+ \qmlproperty flags QtQuick::PinchHandler::acceptedButtons
+
+ This property is not used in PinchHandler.
+*/
+
+/*!
\readonly
\qmlproperty QtQuick::HandlerPoint QtQuick::PinchHandler::centroid
@@ -508,6 +515,9 @@ void QQuickPinchHandler::handlePointerEventImpl(QPointerEvent *event)
The translation of the gesture \l centroid. It is \c (0, 0) when the
gesture begins.
+
+ \note On some touchpads, such as on a \macos trackpad, native gestures do
+ not generate any translation values, and this property stays at \c (0, 0).
*/
QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickpointerdevicehandler.cpp b/src/quick/handlers/qquickpointerdevicehandler.cpp
index e0f082b666..9fe214824f 100644
--- a/src/quick/handlers/qquickpointerdevicehandler.cpp
+++ b/src/quick/handlers/qquickpointerdevicehandler.cpp
@@ -175,7 +175,7 @@ void QQuickPointerDeviceHandler::setAcceptedDevices(QPointingDevice::DeviceTypes
By default, this property is set to
\l {QPointingDevice::PointerType} {PointerDevice.AllPointerTypes}.
If you set it to an OR combination of device types, it will ignore events
- from non-matching events.
+ from non-matching \l {PointerDevice}{devices}.
For example, a control could be made to respond to mouse, touch, and stylus clicks
in some way, but delete itself if tapped with an eraser tool on a graphics tablet,
diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp
index 7921fae46d..ec3c972af3 100644
--- a/src/quick/handlers/qquickpointerhandler.cpp
+++ b/src/quick/handlers/qquickpointerhandler.cpp
@@ -92,7 +92,7 @@ QQuickPointerHandler::~QQuickPointerHandler()
\qmlproperty real PointerHandler::margin
The margin beyond the bounds of the \l {PointerHandler::parent}{parent}
- item within which an event point can activate this handler. For example, on
+ item within which an \l eventPoint can activate this handler. For example, on
a PinchHandler where the \l {PointerHandler::target}{target} is also the
\c parent, it's useful to set this to a distance at least half the width
of a typical user's finger, so that if the \c parent has been scaled down
@@ -125,7 +125,7 @@ void QQuickPointerHandler::setMargin(qreal pointDistanceThreshold)
\qmlproperty int PointerHandler::dragThreshold
\since 5.15
- The distance in pixels that the user must drag an event point in order to
+ The distance in pixels that the user must drag an \l eventPoint in order to
have it treated as a drag gesture.
The default value depends on the platform and screen resolution.
@@ -252,8 +252,8 @@ bool QQuickPointerHandler::isCursorShapeExplicitlySet() const
The \a grabber (subject) will be the Input Handler whose state is changing,
or null if the state change regards an Item.
The \a transition (verb) tells what happened.
- The \a point (object) is the point that was grabbed or ungrabbed.
- EventPoint has the sole responsibility to call this function.
+ The \a point (object) is the \l eventPoint that was grabbed or ungrabbed.
+ QQuickDeliveryAgent calls this function.
The Input Handler must react in whatever way is appropriate, and must
emit the relevant signals (for the benefit of QML code).
A subclass is allowed to override this virtual function, but must always
@@ -707,9 +707,9 @@ bool QQuickPointerHandler::wantsEventPoint(const QPointerEvent *event, const QEv
\qmlproperty bool QtQuick::PointerHandler::active
This holds true whenever this Input Handler has taken sole responsibility
- for handing one or more EventPoints, by successfully taking an exclusive
- grab of those points. This means that it is keeping its properties
- up-to-date according to the movements of those Event Points and actively
+ for handing one or more \l {eventPoint}{eventPoints}, by successfully taking an
+ exclusive grab of those points. This means that it is keeping its properties
+ up-to-date according to the movements of those eventPoints and actively
manipulating its \l target (if any).
*/
void QQuickPointerHandler::setActive(bool active)
@@ -733,7 +733,7 @@ void QQuickPointerHandler::handlePointerEventImpl(QPointerEvent *)
The \l Item which is the scope of the handler; the Item in which it was declared.
The handler will handle events on behalf of this Item, which means a
- pointer event is relevant if at least one of its event points occurs within
+ pointer event is relevant if at least one of its \l {eventPoint}{eventPoints} occurs within
the Item's interior. Initially \l [QML] {target} {target()} is the same, but it
can be reassigned.
@@ -744,7 +744,7 @@ void QQuickPointerHandler::handlePointerEventImpl(QPointerEvent *)
*/
/*!
- \qmlsignal QtQuick::PointerHandler::grabChanged(GrabTransition transition, EventPoint point)
+ \qmlsignal QtQuick::PointerHandler::grabChanged(PointerDevice::GrabTransition transition, eventPoint point)
This signal is emitted when the grab has changed in some way which is
relevant to this handler.
diff --git a/src/quick/handlers/qquickpointhandler.cpp b/src/quick/handlers/qquickpointhandler.cpp
index f4a3a1bb2d..94d1f2f75c 100644
--- a/src/quick/handlers/qquickpointhandler.cpp
+++ b/src/quick/handlers/qquickpointhandler.cpp
@@ -102,7 +102,8 @@ QT_BEGIN_NAMESPACE
PointHandler will not automatically manipulate the \c target item in any way.
You need to use bindings to make it react to the \l point.
- \note On macOS, PointHandler does not react to the trackpad by default.
+ \note On macOS, PointHandler does not react to multiple fingers on the
+ trackpad by default, although it does react to a pressed point (mouse position).
That is because macOS can provide either native gesture recognition, or raw
touchpoints, but not both. We prefer to use the native gesture event in
PinchHandler, so we do not want to disable it by enabling touch. However
@@ -111,7 +112,7 @@ QT_BEGIN_NAMESPACE
want to react to all the touchpoints but do not require the smooth
native-gesture experience.
- \sa MultiPointTouchArea
+ \sa MultiPointTouchArea, HoverHandler, {Pointer Handlers Example}
*/
QQuickPointHandler::QQuickPointHandler(QQuickItem *parent)
@@ -164,6 +165,127 @@ QVector2D QQuickPointHandler::translation() const
return QVector2D(point().position() - point().pressPosition());
}
+/*!
+ \qmlproperty flags PointHandler::acceptedButtons
+
+ The mouse buttons that can activate this PointHandler.
+
+ By default, this property is set to \l {QtQuick::MouseEvent::button} {Qt.LeftButton}.
+ It can be set to an OR combination of mouse buttons, and will ignore events
+ in which other buttons are pressed or held.
+
+ \snippet pointerHandlers/pointHandlerAcceptedButtons.qml 0
+
+ \note On a touchscreen, there are no buttons, so this property does not
+ prevent PointHandler from reacting to touchpoints.
+*/
+
+/*!
+ \qmlproperty flags PointHandler::acceptedDevices
+
+ The types of pointing devices that can activate this PointHandler.
+
+ By default, this property is set to
+ \l{QInputDevice::DeviceType}{PointerDevice.AllDevices}.
+ If you set it to an OR combination of device types, it will ignore events
+ from non-matching \l {PointerDevice}{devices}:
+
+ \snippet pointerHandlers/pointHandler.qml 1
+*/
+
+/*!
+ \qmlproperty flags PointHandler::acceptedPointerTypes
+
+ The types of pointing instruments (finger, stylus, eraser, etc.)
+ that can activate this PointHandler.
+
+ By default, this property is set to
+ \l {QPointingDevice::PointerType} {PointerDevice.AllPointerTypes}.
+ If you set it to an OR combination of device types, it will ignore events
+ from non-matching \l {PointerDevice}{devices}:
+
+ \snippet pointerHandlers/pointHandlerCanvasDrawing.qml 0
+
+ The \l {Pointer Handlers Example} includes a more complex example for
+ drawing on a Canvas with a graphics tablet.
+*/
+
+/*!
+ \qmlproperty flags PointHandler::acceptedModifiers
+
+ If this property is set, PointHandler requires the given keyboard modifiers
+ to be pressed in order to react to \l {PointerEvent}{PointerEvents}, and
+ otherwise ignores them.
+
+ If this property is set to \c Qt.KeyboardModifierMask (the default value),
+ then PointHandler ignores the modifier keys.
+
+ For example, an \l [QML] Item could have two handlers, one of which is
+ enabled only if the required keyboard modifier is pressed:
+
+ \snippet pointerHandlers/pointHandlerAcceptedModifiers.qml 0
+
+ If you set \c acceptedModifiers to an OR combination of modifier keys,
+ it means \e all of those modifiers must be pressed to activate the handler.
+
+ The available modifiers are as follows:
+
+ \value NoModifier No modifier key is allowed.
+ \value ShiftModifier A Shift key on the keyboard must be pressed.
+ \value ControlModifier A Ctrl key on the keyboard must be pressed.
+ \value AltModifier An Alt key on the keyboard must be pressed.
+ \value MetaModifier A Meta key on the keyboard must be pressed.
+ \value KeypadModifier A keypad button must be pressed.
+ \value GroupSwitchModifier X11 only (unless activated on Windows by a command line argument).
+ A Mode_switch key on the keyboard must be pressed.
+ \value KeyboardModifierMask The handler does not care which modifiers are pressed.
+
+ \sa Qt::KeyboardModifier
+*/
+
+/*!
+ \readonly
+ \qmlproperty bool PointHandler::active
+
+ This holds \c true whenever the constraints are satisfied and this
+ PointHandler is reacting. This means that it is keeping its properties
+ up-to-date according to the movements of the \l {eventPoint}{eventPoints}
+ that satisfy the constraints.
+*/
+
+/*!
+ \internal
+ \qmlproperty flags PointHandler::dragThreshold
+
+ This property is not used in PointHandler.
+*/
+
+/*!
+ \qmlproperty real PointHandler::margin
+
+ The margin beyond the bounds of the \l {PointerHandler::parent}{parent}
+ item within which an \l eventPoint can activate this handler.
+
+ The default value is \c 0.
+
+ \snippet pointerHandlers/pointHandlerMargin.qml 0
+*/
+
+/*!
+ \qmlproperty real PointHandler::target
+
+ A property that can conveniently hold an Item to be manipulated or to show
+ feedback. Unlike other \l {Qt Quick Input Handlers}{Pointer Handlers},
+ PointHandler does not do anything with the \c target on its own: you
+ usually need to create reactive bindings to properties such as
+ \l SinglePointHandler::point and \l PointHandler::active. If you declare
+ an Item instance here, you need to explicitly set its \l {Item::}{parent},
+ because PointHandler is not an Item.
+
+ By default, it is the same as the \l {PointerHandler::}{parent}, the Item
+ within which the handler is declared.
+*/
+
QT_END_NAMESPACE
#include "moc_qquickpointhandler_p.cpp"
diff --git a/src/quick/handlers/qquicksinglepointhandler.cpp b/src/quick/handlers/qquicksinglepointhandler.cpp
index 6c60d56c8b..22b475637a 100644
--- a/src/quick/handlers/qquicksinglepointhandler.cpp
+++ b/src/quick/handlers/qquicksinglepointhandler.cpp
@@ -209,7 +209,7 @@ QQuickHandlerPoint QQuickSinglePointHandler::point() const
\readonly
\qmlproperty HandlerPoint QtQuick::SinglePointHandler::point
- The event point currently being handled. When no point is currently being
+ The \l eventPoint currently being handled. When no point is currently being
handled, this object is reset to default values (all coordinates are 0).
*/
diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp
index 316293ea06..3abb366676 100644
--- a/src/quick/handlers/qquicktaphandler.cpp
+++ b/src/quick/handlers/qquicktaphandler.cpp
@@ -84,7 +84,7 @@ int QQuickTapHandler::m_touchMultiTapDistanceSquared(-1);
QStyleHints::touchDoubleTapDistance() with touch, and the time between
taps must not exceed QStyleHints::mouseDoubleClickInterval().
- \sa MouseArea
+ \sa MouseArea, {Pointer Handlers Example}
*/
QQuickTapHandler::QQuickTapHandler(QQuickItem *parent)
@@ -182,7 +182,7 @@ void QQuickTapHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point
/*!
\qmlproperty real QtQuick::TapHandler::longPressThreshold
- The time in seconds that an event point must be pressed in order to
+ The time in seconds that an \l eventPoint must be pressed in order to
trigger a long press gesture and emit the \l longPressed() signal.
If the point is released before this time limit, a tap can be detected
if the \l gesturePolicy constraint is satisfied. The default value is
@@ -229,34 +229,77 @@ void QQuickTapHandler::timerEvent(QTimerEvent *event)
The \c gesturePolicy also affects grab behavior as described below.
- \value TapHandler.DragThreshold
- (the default value) The event point must not move significantly.
- If the mouse, finger or stylus moves past the system-wide drag
- threshold (QStyleHints::startDragDistance), the tap gesture is
- canceled, even if the button or finger is still pressed. This policy
- can be useful whenever TapHandler needs to cooperate with other
- input handlers (for example \l DragHandler) or event-handling Items
- (for example QtQuick Controls), because in this case TapHandler
- will not take the exclusive grab, but merely a
- \l {QPointerEvent::addPassiveGrabber()}{passive grab}.
-
- \value TapHandler.WithinBounds
- If the event point leaves the bounds of the \c parent Item, the tap
- gesture is canceled. The TapHandler will take the
- \l {QPointerEvent::setExclusiveGrabber}{exclusive grab} on
- press, but will release the grab as soon as the boundary constraint
- is no longer satisfied.
-
- \value TapHandler.ReleaseWithinBounds
- At the time of release (the mouse button is released or the finger
- is lifted), if the event point is outside the bounds of the
- \c parent Item, a tap gesture is not recognized. This corresponds to
- typical behavior for button widgets: you can cancel a click by
- dragging outside the button, and you can also change your mind by
- dragging back inside the button before release. Note that it's
- necessary for TapHandler to take the
- \l {QPointerEvent::setExclusiveGrabber}{exclusive grab} on press
- and retain it until release in order to detect this gesture.
+ \table
+ \header
+ \li Constant
+ \li Description
+ \row
+ \li \c TapHandler.DragThreshold
+ \image pointerHandlers/tapHandlerOverlappingButtons.webp
+ Grab on press: \e passive
+ \li (the default value) The \l eventPoint must not move significantly.
+ If the mouse, finger or stylus moves past the system-wide drag
+ threshold (QStyleHints::startDragDistance), the tap gesture is
+ canceled, even if the device or finger is still pressed. This policy
+ can be useful whenever TapHandler needs to cooperate with other
+ input handlers (for example \l DragHandler) or event-handling Items
+ (for example \l {Qt Quick Controls}), because in this case TapHandler
+ will not take the exclusive grab, but merely a
+ \l {QPointerEvent::addPassiveGrabber()}{passive grab}.
+ That is, \c DragThreshold is especially useful to \e augment
+ existing behavior: it reacts to tap/click/long-press even when
+ another item or handler is already reacting, perhaps even in a
+ different layer of the UI. The following snippet shows one
+ TapHandler as used in one component; but if we stack up two
+ instances of the component, you will see the handlers in both of them
+ react simultaneously when a press occurs over both of them, because
+ the passive grab does not stop event propagation:
+ \quotefromfile pointerHandlers/tapHandlerOverlappingButtons.qml
+ \skipto Item
+ \printuntil component Button
+ \skipto TapHandler
+ \printuntil }
+ \skipuntil Text {
+ \skipuntil }
+ \printuntil Button
+ \printuntil Button
+ \printuntil }
+
+ \row
+ \li \c TapHandler.WithinBounds
+ \image pointerHandlers/tapHandlerButtonWithinBounds.webp
+ Grab on press: \e exclusive
+ \li If the \l eventPoint leaves the bounds of the \c parent Item, the tap
+ gesture is canceled. The TapHandler will take the
+ \l {QPointerEvent::setExclusiveGrabber}{exclusive grab} on
+ press, but will release the grab as soon as the boundary constraint
+ is no longer satisfied.
+ \snippet pointerHandlers/tapHandlerButtonWithinBounds.qml 1
+
+ \row
+ \li \c TapHandler.ReleaseWithinBounds
+ \image pointerHandlers/tapHandlerButtonReleaseWithinBounds.webp
+ Grab on press: \e exclusive
+ \li At the time of release (the mouse button is released or the finger
+ is lifted), if the \l eventPoint is outside the bounds of the
+ \c parent Item, a tap gesture is not recognized. This corresponds to
+ typical behavior for button widgets: you can cancel a click by
+ dragging outside the button, and you can also change your mind by
+ dragging back inside the button before release. Note that it's
+ necessary for TapHandler to take the
+ \l {QPointerEvent::setExclusiveGrabber}{exclusive grab} on press
+ and retain it until release in order to detect this gesture.
+ \snippet pointerHandlers/tapHandlerButtonReleaseWithinBounds.qml 1
+ \endtable
+
+ The \l {Pointer Handlers Example} demonstrates some use cases for these.
+
+ \note If you find that TapHandler is reacting in cases that conflict with
+ some other behavior, the first thing you should try is to think about which
+ \c gesturePolicy is appropriate. If you cannot fix it by changing \c gesturePolicy,
+ some cases are better served by adjusting \l {PointerHandler::}{grabPermissions},
+ either in this handler, or in another handler that should \e prevent TapHandler
+ from reacting.
*/
void QQuickTapHandler::setGesturePolicy(QQuickTapHandler::GesturePolicy gesturePolicy)
{
@@ -273,7 +316,7 @@ void QQuickTapHandler::setGesturePolicy(QQuickTapHandler::GesturePolicy gestureP
Holds true whenever the mouse or touch point is pressed,
and any movement since the press is compliant with the current
- \l gesturePolicy. When the event point is released or the policy is
+ \l gesturePolicy. When the \l eventPoint is released or the policy is
violated, \e pressed will change to false.
*/
void QQuickTapHandler::setPressed(bool press, bool cancel, QPointerEvent *event, QEventPoint &point)
diff --git a/src/quick/handlers/qquickwheelhandler.cpp b/src/quick/handlers/qquickwheelhandler.cpp
index dd2e6134c0..f1e40ba35c 100644
--- a/src/quick/handlers/qquickwheelhandler.cpp
+++ b/src/quick/handlers/qquickwheelhandler.cpp
@@ -81,7 +81,7 @@ Q_LOGGING_CATEGORY(lcWheelHandler, "qt.quick.handler.wheel")
WheelHandler handles only a rotating mouse wheel by default; this
can be changed by setting acceptedDevices.
- \sa MouseArea, Flickable
+ \sa MouseArea, Flickable, {Pointer Handlers Example}
*/
QQuickWheelHandler::QQuickWheelHandler(QQuickItem *parent)
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index e13c0f6dae..89fafbe44d 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -288,7 +288,7 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
QPainter instead of the more expensive and likely less performing
JavaScript and Context2D approach.
- \sa Context2D QQuickPaintedItem
+ \sa Context2D, QQuickPaintedItem, {Pointer Handlers Example}
*/
QQuickCanvasItem::QQuickCanvasItem(QQuickItem *parent)
@@ -652,6 +652,10 @@ void QQuickCanvasItem::invalidateSceneGraph()
d->textureProvider = nullptr;
delete d->nodeTexture;
d->nodeTexture = nullptr;
+
+ // As we can expect(/hope) that the SG will be "good again", we can requestPaint ( which does 'markDirty(canvasWindow);' )
+ // Otherwise this Canvas will be "blank" when SG comes back
+ requestPaint();
}
void QQuickCanvasItem::schedulePolish()
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 3c3ca3ea2b..e050561ac5 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -2257,11 +2257,9 @@ void QQuickFlickable::setContentWidth(qreal w)
d->contentItem->setWidth(w);
d->hData.markExtentsDirty();
// Make sure that we're entirely in view.
- if ((!d->pressed && !d->hData.moving && !d->vData.moving) || d->hData.dragging) {
- d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging;
+ if (!d->pressed && !d->hData.moving && !d->vData.moving) {
d->fixupMode = QQuickFlickablePrivate::Immediate;
d->fixupX();
- d->hData.contentPositionChangedExternallyDuringDrag = false;
} else if (!d->pressed && d->hData.fixingUp) {
d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
d->fixupX();
@@ -2288,11 +2286,9 @@ void QQuickFlickable::setContentHeight(qreal h)
d->contentItem->setHeight(h);
d->vData.markExtentsDirty();
// Make sure that we're entirely in view.
- if ((!d->pressed && !d->hData.moving && !d->vData.moving) || d->vData.dragging) {
- d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging;
+ if (!d->pressed && !d->hData.moving && !d->vData.moving) {
d->fixupMode = QQuickFlickablePrivate::Immediate;
d->fixupY();
- d->vData.contentPositionChangedExternallyDuringDrag = false;
} else if (!d->pressed && d->vData.fixingUp) {
d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
d->fixupY();
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 4658f7c7cb..c748bb9f43 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -120,6 +120,7 @@ public:
dragStartOffset = 0;
fixingUp = false;
inOvershoot = false;
+ contentPositionChangedExternallyDuringDrag = false;
}
void markExtentsDirty() {
diff --git a/src/quick/items/qquickflipable.cpp b/src/quick/items/qquickflipable.cpp
index a338985622..87112c8b93 100644
--- a/src/quick/items/qquickflipable.cpp
+++ b/src/quick/items/qquickflipable.cpp
@@ -39,7 +39,7 @@
#include "qquickflipable_p.h"
#include "qquickitem_p.h"
-
+#include "qquicktranslate_p.h"
#include <QtQml/qqmlinfo.h>
@@ -237,9 +237,20 @@ void QQuickFlipable::updatePolish()
d->updateSide();
}
-// determination on the currently visible side of the flipable
-// has to be done on the complete scene transform to give
-// correct results.
+/*! \internal
+ Flipable must use the complete scene transform to correctly determine the
+ currently visible side.
+
+ It must also be independent of camera distance, in case the contents are
+ too wide: for rotation transforms we simply call QMatrix4x4::rotate(),
+ whereas QQuickRotation::applyTo(QMatrix4x4*) calls
+ QMatrix4x4::projectedRotate() which by default assumes the camera distance
+ is 1024 virtual pixels. So for example if contents inside Flipable are to
+ be flipped around the y axis, and are wider than 1024*2, some of the
+ rendering goes behind the "camera". That's expected for rendering (since we
+ didn't provide API to change camera distance), but not ok for deciding when
+ to flip.
+*/
void QQuickFlipablePrivate::updateSide()
{
Q_Q(QQuickFlipable);
@@ -249,8 +260,39 @@ void QQuickFlipablePrivate::updateSide()
sideDirty = false;
- QTransform sceneTransform;
- itemToParentTransform(sceneTransform);
+ QMatrix4x4 sceneTransform;
+
+ const qreal tx = x.value();
+ const qreal ty = y.value();
+ if (!qFuzzyIsNull(tx) || !qFuzzyIsNull(ty))
+ sceneTransform.translate(tx, ty);
+
+ for (const auto *transform : std::as_const(transforms)) {
+ if (const auto *rot = qobject_cast<const QQuickRotation *>(transform)) {
+ // rotation is a special case: we want to call rotate() instead of projectedRotate()
+ const auto angle = rot->angle();
+ const auto axis = rot->axis();
+ if (!(qFuzzyIsNull(angle) || axis.isNull())) {
+ sceneTransform.translate(rot->origin());
+ sceneTransform.rotate(angle, axis.x(), axis.y(), axis.z());
+ sceneTransform.translate(-rot->origin());
+ }
+ } else {
+ transform->applyTo(&sceneTransform);
+ }
+ }
+
+ const bool hasRotation = !qFuzzyIsNull(rotation());
+ const bool hasScale = !qFuzzyCompare(scale(), 1);
+ if (hasScale || hasRotation) {
+ QPointF tp = computeTransformOrigin();
+ sceneTransform.translate(tp.x(), tp.y());
+ if (hasScale)
+ sceneTransform.scale(scale(), scale());
+ if (hasRotation)
+ sceneTransform.rotate(rotation(), 0, 0, 1);
+ sceneTransform.translate(-tp.x(), -tp.y());
+ }
QPointF p1(0, 0);
QPointF p2(1, 0);
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 54e6d27be7..4426c26cab 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -494,6 +494,8 @@ qreal QQuickImage::paintedHeight() const
\note \e {Changing this property dynamically causes the image source to be reloaded,
potentially even from the network, if it is not in the disk cache.}
+
+ \sa {Pointer Handlers Example}
*/
/*!
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index 9ed3eef2a6..596cd7d63a 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -327,8 +327,10 @@ void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
const qreal targetDevicePixelRatio = (window() ? window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio());
d->devicePixelRatio = 1.0;
bool updatedDevicePixelRatio = false;
- if (d->sourcesize.isValid() || isScalableImageFormat(d->url))
+ if (d->sourcesize.isValid()
+ || (isScalableImageFormat(d->url) && d->url.scheme() != QLatin1String("image"))) {
updatedDevicePixelRatio = d->updateDevicePixelRatio(targetDevicePixelRatio);
+ }
if (!updatedDevicePixelRatio) {
// (possible) local file: loadUrl and d->devicePixelRatio will be modified if
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index d1bd9877d2..dfa88c0a04 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -8003,7 +8003,7 @@ void QQuickItem::setKeepTouchGrab(bool keep)
Returns \c true if this item contains \a point, which is in local coordinates;
returns \c false otherwise. This is the same check that is used for
hit-testing a QEventPoint during event delivery, and is affected by
- containmentMask() if it is set.
+ \l containmentMask if it is set.
*/
/*!
Returns \c true if this item contains \a point, which is in local coordinates;
@@ -8011,7 +8011,7 @@ void QQuickItem::setKeepTouchGrab(bool keep)
This function can be overridden in order to handle point collisions in items
with custom shapes. The default implementation checks whether the point is inside
- containmentMask() if it is set, or inside the bounding box otherwise.
+ \l containmentMask() if it is set, or inside the bounding box otherwise.
\note This method is used for hit-testing each QEventPoint during event
delivery, so the implementation should be kept as lightweight as possible.
@@ -8040,10 +8040,10 @@ bool QQuickItem::contains(const QPointF &point) const
\qmlproperty QObject* QtQuick::Item::containmentMask
\since 5.11
This property holds an optional mask for the Item to be used in the
- QtQuick::Item::contains() method. Its main use is currently to determine
+ \l contains() method. Its main use is currently to determine
whether a \l {QPointerEvent}{pointer event} has landed into the item or not.
- By default the \l contains method will return true for any point
+ By default the \c contains() method will return true for any point
within the Item's bounding box. \c containmentMask allows for
more fine-grained control. For example, if a custom C++
QQuickItem subclass with a specialized contains() method
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 144e71cc88..fbffde1c48 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -196,4 +196,138 @@ void QQuickItemsModule::defineModule()
qt_quickitems_defineModule();
}
+/*!
+ \qmltype PointerEvent
+ \instantiates QPointerEvent
+ \inqmlmodule QtQuick
+ \brief QML equivalent for \l QPointerEvent.
+
+ PointerEvent is the QML name of the QPointerEvent class.
+*/
+
+/*!
+ \qmltype PointerDevice
+ \instantiates QPointingDevice
+ \inqmlmodule QtQuick
+ \brief QML equivalent for \l QPointingDevice.
+
+ PointerDevice is the QML name of the QPointingDevice class.
+ It has the same properties and enums as \l QPointingDevice.
+*/
+
+/*!
+ \qmlproperty enumeration PointerDevice::deviceType
+
+ This property tells the type of device that generated a PointerEvent.
+
+ Valid values are:
+
+ \value PointerDevice.Unknown The device cannot be identified.
+ \value PointerDevice.Mouse A mouse.
+ \value PointerDevice.TouchScreen A touchscreen.
+ \value PointerDevice.TouchPad A touchpad or trackpad.
+ \value PointerDevice.Stylus A stylus on a graphics tablet.
+ \value PointerDevice.Airbrush An airbrush on a graphics tablet.
+ \value PointerDevice.Puck A digitizer with crosshairs, on a graphics tablet.
+
+ \sa QInputDevice::DeviceType, PointerDeviceHandler::acceptedDevices
+*/
+
+/*!
+ \qmlproperty enumeration PointerDevice::pointerType
+
+ This property tells what is interacting with the PointerDevice.
+
+ There is some redundancy between this property and \l deviceType.
+ For example, if a touchscreen is used, then \c deviceType is
+ \c TouchScreen and \c pointerType is \c Finger. But on a graphics
+ tablet, it's often possible for both ends of the stylus to be used,
+ and programs need to distinguish them.
+ \l PointerDeviceHandler::acceptedDevices and
+ \l PointerDeviceHandler::acceptedPointerTypes can be used in combination
+ to filter the subset of events that a particular handler should react to.
+
+ Valid values are:
+
+ \value PointerDevice.Unknown The device cannot be identified.
+ \value PointerDevice.Generic A mouse or a device that emulates a mouse.
+ \value PointerDevice.Finger A finger on a touchscreen.
+ \value PointerDevice.Pen A stylus on a graphics tablet.
+ \value PointerDevice.Eraser An eraser on a graphics tablet.
+ \value PointerDevice.Cursor A digitizer with crosshairs, on a graphics tablet.
+
+ \sa QPointingDevice::PointerType, PointerDeviceHandler::acceptedPointerTypes
+*/
+
+/*!
+ \qmlproperty int PointerDevice::maximumPoints
+
+ This property tells the maximum number of simultaneous touch points
+ (fingers) that can be detected.
+*/
+
+/*!
+ \qmlproperty int PointerDevice::buttonCount
+
+ This property tells the maximum number of on-device buttons that can be
+ detected.
+*/
+
+/*!
+ \qmltype pointingDeviceUniqueId
+ \instantiates QPointingDeviceUniqueId
+ \inqmlmodule QtQuick
+ \brief QML equivalent for \l QPointingDeviceUniqueId.
+
+ pointingDeviceUniqueId is the QML name of the QPointingDeviceUniqueId class.
+*/
+
+/*!
+ \qmlproperty qint64 pointingDeviceUniqueId::numericId
+
+ This property gives the numeric ID of the \l PointerDevice, if available;
+ otherwise it is \c -1.
+*/
+
+/*!
+ \qmlproperty pointingDeviceUniqueId PointerDevice::uniqueId
+
+ This property may provide a unique ID for the device, if available. For
+ example, a graphics tablet stylus device may have a unique serial number.
+
+ \sa eventPoint, QEventPoint::uniqueId()
+*/
+
+/*!
+ \qmlsignal PointerDevice::grabChanged(QtObject grabber, enumeration transition, PointerEvent event, eventPoint point)
+
+ This signal is emitted when the \a grabber object gains or loses an
+ exclusive or passive grab of \a point during delivery of \a event.
+ The \a transition tells what happened, from the perspective of the
+ \c grabber object, which may be either an \l Item or an
+ \l {Qt Quick Input Handlers}{Input Handler}.
+
+ Valid values for \a transition are:
+
+ \value GrabExclusive
+ The \a grabber has taken primary responsibility for handling the \a point.
+ \value UngrabExclusive
+ The \a grabber has given up its previous exclusive grab.
+ \value CancelGrabExclusive
+ The exclusive grab of \a grabber has been taken over or cancelled.
+ \value GrabPassive
+ The \a grabber has acquired a passive grab, to monitor the \a point.
+ \value UngrabPassive
+ The \a grabber has given up its previous passive grab.
+ \value CancelGrabPassive
+ The previous passive grab has terminated abnormally.
+
+ \note A grab transition from one object to another results in two signals,
+ to notify that one object has lost its grab, and to notify that there is
+ another grabber. In other cases, when transitioning to or from a non-grabbing
+ state, only one signal is emitted.
+
+ \sa QPointerEvent::setExclusiveGrabber(), QPointerEvent::addPassiveGrabber(), QPointerEvent::removePassiveGrabber()
+*/
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index b00e827d51..faa03fa9ae 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -1968,6 +1968,9 @@ void QQuickItemViewPrivate::layout()
transitioner->resetTargetLists();
}
+ if (!currentItem)
+ updateCurrent(currentIndex);
+
runDelayedRemoveTransition = false;
inLayout = false;
}
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 786d663155..58f031a9eb 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -2741,7 +2741,8 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
\c section.delegate holds the delegate component for each section. The
default \l {QQuickItem::z}{stacking order} of section delegate instances
- is \c 2.
+ is \c 2. If you declare a \c required property named "section" in it,
+ that property will contain the section's title.
\c section.labelPositioning determines whether the current and/or
next section labels stick to the start/end of the view, and whether
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index ea1aa7b0c9..1f5c55cffe 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -804,7 +804,7 @@ void QQuickLoader::componentComplete()
{
Q_D(QQuickLoader);
QQuickItem::componentComplete();
- if (active()) {
+ if (active() && (status() != Ready)) {
if (d->loadingFromSource)
d->createComponent();
d->load();
diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp
index ce570a743c..52c830c14a 100644
--- a/src/quick/items/qquickrectangle.cpp
+++ b/src/quick/items/qquickrectangle.cpp
@@ -578,8 +578,13 @@ QSGNode *QQuickRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
if (d->pen && d->pen->isValid()) {
rectangle->setPenColor(d->pen->color());
- rectangle->setPenWidth(d->pen->width());
- rectangle->setAligned(d->pen->pixelAligned());
+ qreal penWidth = d->pen->width();
+ if (d->pen->pixelAligned()) {
+ qreal dpr = window() ? window()->effectiveDevicePixelRatio() : 1.0;
+ penWidth = qRound(penWidth * dpr) / dpr; // Ensures integer width after dpr scaling
+ }
+ rectangle->setPenWidth(penWidth);
+ rectangle->setAligned(false); // width rounding already done, so the Node should not do it
} else {
rectangle->setPenWidth(0);
}
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index c87ea5b1f4..2d48a39be8 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -537,7 +537,7 @@ void QQuickRenderControlPrivate::maybeUpdate()
Reimplemented in subclasses to return the real window this render control
is rendering into.
- If \a offset in non-null, it is set to the offset of the control
+ If \a offset is non-null, it is set to the offset of the control
inside the window.
\note While not mandatory, reimplementing this function becomes essential for
@@ -549,7 +549,7 @@ void QQuickRenderControlPrivate::maybeUpdate()
/*!
Returns the real window that \a win is being rendered to, if any.
- If \a offset in non-null, it is set to the offset of the rendering
+ If \a offset is non-null, it is set to the offset of the rendering
inside its window.
*/
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index 6ef868884a..5c2f113fdc 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -1387,7 +1387,7 @@ bool QQuickShaderEffectImpl::updateShader(Shader shaderType, const QUrl &fileUrl
// provided and monitored like with an application-provided shader.
QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
v.name = QByteArrayLiteral("source");
- v.bindPoint = 0; // fake
+ v.bindPoint = 1; // fake, must match the default source bindPoint in qquickshadereffectnode.cpp
v.type = texturesSeparate ? QSGGuiThreadShaderEffectManager::ShaderInfo::Texture
: QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
m_shaders[shaderType].shaderInfo.variables.append(v);
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index e35c766ab6..ddc43c10ed 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -352,6 +352,7 @@ void QQuickSpriteEngine::startAssemblingImage()
return;
m_loaded = false;
m_errorsPrinted = false;
+ m_sprites.clear();
//This could also trigger the start of the image loading in Sprites, however that currently happens in Sprite::setSource
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 2fed5b1cfc..9f259166df 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -688,8 +688,6 @@ Q_LOGGING_CATEGORY(lcTableViewDelegateLifecycle, "qt.quick.tableview.lifecycle")
#define Q_TABLEVIEW_ASSERT(cond, output) Q_ASSERT((cond) || [&](){ dumpTable(); qWarning() << "output:" << output; return false;}())
static const Qt::Edge allTableEdges[] = { Qt::LeftEdge, Qt::RightEdge, Qt::TopEdge, Qt::BottomEdge };
-static const int kEdgeIndexNotSet = -2;
-static const int kEdgeIndexAtEnd = -3;
static const char* kRequiredProperty = "_qt_isrequiredpropery_selected";
@@ -2340,11 +2338,6 @@ void QQuickTableViewPrivate::processRebuildTable()
if (rebuildState == RebuildState::LayoutTable) {
layoutAfterLoadingInitialTable();
- if (!moveToNextRebuildState())
- return;
- }
-
- if (rebuildState == RebuildState::LoadAndUnloadAfterLayout) {
loadAndUnloadVisibleEdges();
if (!moveToNextRebuildState())
return;
@@ -2364,6 +2357,12 @@ void QQuickTableViewPrivate::processRebuildTable()
return;
}
+ if (rebuildState == RebuildState::UpdateContentSize) {
+ updateContentSize();
+ if (!moveToNextRebuildState())
+ return;
+ }
+
const bool preload = (rebuildOptions & RebuildOption::All
&& reusableFlag == QQmlTableInstanceModel::Reusable);
@@ -2607,23 +2606,31 @@ void QQuickTableViewPrivate::loadInitialTable()
loadAndUnloadVisibleEdges();
}
-void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
+void QQuickTableViewPrivate::updateContentSize()
{
- clearEdgeSizeCache();
- relayoutTableItems();
- syncLoadedTableRectFromLoadedTable();
-
- if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded()) {
+ const bool allColumnsLoaded = atTableEnd(Qt::LeftEdge) && atTableEnd(Qt::RightEdge);
+ if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded) {
updateAverageColumnWidth();
updateContentWidth();
}
- if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded()) {
+ const bool allRowsLoaded = atTableEnd(Qt::TopEdge) && atTableEnd(Qt::BottomEdge);
+ if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded) {
updateAverageRowHeight();
updateContentHeight();
}
updateExtents();
+}
+
+void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
+{
+ clearEdgeSizeCache();
+ relayoutTableItems();
+ syncLoadedTableRectFromLoadedTable();
+
+ updateContentSize();
+
adjustViewportXAccordingToAlignment();
adjustViewportYAccordingToAlignment();
}
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index 6fd05c5508..9893cd97e7 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -71,6 +71,8 @@ Q_DECLARE_LOGGING_CATEGORY(lcTableViewDelegateLifecycle)
static const qreal kDefaultRowHeight = 50;
static const qreal kDefaultColumnWidth = 50;
+static const int kEdgeIndexNotSet = -2;
+static const int kEdgeIndexAtEnd = -3;
class FxTableItem;
class QQuickTableSectionSizeProviderPrivate;
@@ -201,9 +203,9 @@ public:
LoadInitalTable,
VerifyTable,
LayoutTable,
- LoadAndUnloadAfterLayout,
CancelOvershootBottomRight,
CancelOvershootTopLeft,
+ UpdateContentSize,
PreloadColumns,
PreloadRows,
MovePreloadedItemsToPool,
@@ -400,6 +402,9 @@ public:
int nextVisibleEdgeIndex(Qt::Edge edge, int startIndex);
int nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge);
+ inline bool atTableEnd(Qt::Edge edge) {
+ return nextVisibleEdgeIndexAroundLoadedTable(edge) == kEdgeIndexAtEnd;
+ }
bool allColumnsLoaded();
bool allRowsLoaded();
inline int edgeToArrayIndex(Qt::Edge edge);
@@ -441,6 +446,8 @@ public:
void scheduleRebuildTable(QQuickTableViewPrivate::RebuildOptions options);
+ void updateContentSize();
+
QTypeRevision resolveImportVersion();
void createWrapperModel();
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 2df40bd272..ec1416768e 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -2986,6 +2986,7 @@ void QQuickText::hoverLeaveEvent(QHoverEvent *event)
/*!
\qmlproperty int QtQuick::Text::renderTypeQuality
+ \since 6.0
Override the default rendering type quality for this component. This is a low-level
customization which can be ignored in most cases. It currently only has an effect
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index b3401200c8..763607f730 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -209,10 +209,7 @@ void QQuickTextNodeEngine::addTextDecorations(const QVarLengthArray<TextDecorati
{
QRectF &rect = textDecoration.rect;
- rect.setY(qRound(rect.y()
- + m_currentLine.ascent()
- + (m_currentLine.leadingIncluded() ? m_currentLine.leading() : qreal(0.0f))
- + offset));
+ rect.setY(qRound(rect.y() + m_currentLine.ascent() + offset));
rect.setHeight(thickness);
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 4922148b27..19b508cecb 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -3838,7 +3838,7 @@ QSGRendererInterface *QQuickWindow::rendererInterface() const
graphics API based on the platform and other conditions, set \a api to
QSGRendererInterface::Unknown.
- \since 5.8
+ \since 6.0
*/
void QQuickWindow::setGraphicsApi(QSGRendererInterface::GraphicsApi api)
{
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp
index c8ecf49767..cf369f55a6 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.cpp
+++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp
@@ -406,8 +406,10 @@ const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_ColoredPoint2D()
Geometry objects are constructed by default with DrawTriangleStrip as
the drawing mode.
- The attribute structure is assumed to be POD and the geometry object
- assumes this will not go away. There is no memory management involved.
+ \note \a attributes and the \l Attribute objects referenced by it must
+ stay valid for the entire lifetime of the QSGGeometry.
+ QSGGeometry stores a reference to \a attributes and does not delete
+ the \l Attribute objects.
*/
QSGGeometry::QSGGeometry(const QSGGeometry::AttributeSet &attributes,
diff --git a/src/quick/scenegraph/coreapi/qsgtexture.cpp b/src/quick/scenegraph/coreapi/qsgtexture.cpp
index 8ee1220b0d..b79999c3ea 100644
--- a/src/quick/scenegraph/coreapi/qsgtexture.cpp
+++ b/src/quick/scenegraph/coreapi/qsgtexture.cpp
@@ -716,6 +716,7 @@ namespace QNativeInterface {
\inmodule QtQuick
\ingroup native-interfaces
\ingroup native-interfaces-qsgtexture
+ \inheaderfile QSGTexture
\brief Provides access to and enables adopting OpenGL texture objects.
\since 6.0
*/
@@ -816,6 +817,7 @@ namespace QNativeInterface {
\inmodule QtQuick
\ingroup native-interfaces
\ingroup native-interfaces-qsgtexture
+ \inheaderfile QSGTexture
\brief Provides access to and enables adopting Direct3D 11 texture objects.
\since 6.0
*/
@@ -876,6 +878,7 @@ namespace QNativeInterface {
\inmodule QtQuick
\ingroup native-interfaces
\ingroup native-interfaces-qsgtexture
+ \inheaderfile QSGTexture
\brief Provides access to and enables adopting Metal texture objects.
\since 6.0
*/
@@ -923,6 +926,7 @@ namespace QNativeInterface {
\inmodule QtQuick
\ingroup native-interfaces
\ingroup native-interfaces-qsgtexture
+ \inheaderfile QSGTexture
\brief Provides access to and enables adopting Vulkan image objects.
\since 6.0
*/
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 3b3f4c4abb..df0592cad1 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -508,9 +508,11 @@ void QSGTextMaskMaterial::populate(const QPointF &p,
bool supportsSubPixelPositions = fontD->fontEngine->supportsHorizontalSubPixelPositions();
for (int i=0; i<glyphIndexes.size(); ++i) {
QPointF glyphPosition = glyphPositions.at(i) + position;
+ QFixedPoint fixedPointPosition = fixedPointPositions.at(i);
+
QFixed subPixelPosition;
if (supportsSubPixelPositions)
- subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPosition.x() * glyphCacheScaleX));
+ subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(fixedPointPosition.x.toReal() * glyphCacheScaleX));
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i),
QFixedPoint(subPixelPosition, 0));
diff --git a/src/quick/scenegraph/qsgrhishadereffectnode.cpp b/src/quick/scenegraph/qsgrhishadereffectnode.cpp
index e5903077a5..5575731675 100644
--- a/src/quick/scenegraph/qsgrhishadereffectnode.cpp
+++ b/src/quick/scenegraph/qsgrhishadereffectnode.cpp
@@ -117,6 +117,12 @@ void QSGRhiShaderLinker::feedSamplers(const QSGShaderEffectNode::ShaderData &sha
const QSGShaderEffectNode::VariableData &vd(shader.varData.at(i));
if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
Q_ASSERT(vd.specialType == QSGShaderEffectNode::VariableData::Source);
+
+#ifndef QT_NO_DEBUG
+ int existingBindPoint = m_samplerNameMap.value(var.name, -1);
+ Q_ASSERT(existingBindPoint < 0 || existingBindPoint == var.bindPoint);
+#endif
+
m_samplers.insert(var.bindPoint, vd.value);
m_samplerNameMap.insert(var.name, var.bindPoint);
}
@@ -125,6 +131,12 @@ void QSGRhiShaderLinker::feedSamplers(const QSGShaderEffectNode::ShaderData &sha
for (int idx : *dirtyIndices) {
const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &var(shader.shaderInfo.variables.at(idx));
const QSGShaderEffectNode::VariableData &vd(shader.varData.at(idx));
+
+#ifndef QT_NO_DEBUG
+ int existingBindPoint = m_samplerNameMap.value(var.name, -1);
+ Q_ASSERT(existingBindPoint < 0 || existingBindPoint == var.bindPoint);
+#endif
+
m_samplers.insert(var.bindPoint, vd.value);
m_samplerNameMap.insert(var.name, var.bindPoint);
}
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index def4248118..bdb47653df 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -394,11 +394,12 @@ void QQuickTransformAnimatorJob::Helper::sync()
wasSynced = true;
}
+ // We update the node before checking on dirty, as the node might have changed without the animator running
+ node = d->itemNode();
+
if (dirty == 0)
return;
- node = d->itemNode();
-
if (dirty & QQuickItemPrivate::Position) {
dx = item->x();
dy = item->y();
diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp
index 2cf52347a2..b8167ebed3 100644
--- a/src/quick/util/qquickdeliveryagent.cpp
+++ b/src/quick/util/qquickdeliveryagent.cpp
@@ -2401,8 +2401,11 @@ bool QQuickDeliveryAgentPrivate::sendFilteredPointerEventImpl(QPointerEvent *eve
if (filteringParent->childMouseEventFilter(receiver, &filteringParentTouchEvent)) {
qCDebug(lcTouch) << "touch event intercepted by childMouseEventFilter of " << filteringParent;
skipDelivery.append(filteringParent);
- for (auto point : filteringParentTouchEvent.points())
- event->setExclusiveGrabber(point, filteringParent);
+ for (auto point : filteringParentTouchEvent.points()) {
+ const QQuickItem *exclusiveGrabber = qobject_cast<const QQuickItem *>(event->exclusiveGrabber(point));
+ if (!exclusiveGrabber || !exclusiveGrabber->keepTouchGrab())
+ event->setExclusiveGrabber(point, filteringParent);
+ }
return true;
} else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
!filteringParent->acceptTouchEvents()) {
diff --git a/src/quick/util/qquicktransition.cpp b/src/quick/util/qquicktransition.cpp
index 46c3f04bc8..64394ee285 100644
--- a/src/quick/util/qquicktransition.cpp
+++ b/src/quick/util/qquicktransition.cpp
@@ -82,6 +82,11 @@ QT_BEGIN_NAMESPACE
values can be set to restrict the animations to only be applied when changing
from one particular state to another.
+ Top-level animations within a transition are run in parallel. To run them
+ sequentially, define them within a SequentialAnimation:
+
+ \snippet qml/transition-reversible.qml sequential animations
+
To define multiple Transitions, specify \l Item::transitions as a list:
\snippet qml/transitions-list.qml list of transitions
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate.qml
index f7e27978c5..866e711481 100644
--- a/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate.qml
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate.qml
@@ -45,6 +45,7 @@ ListView {
required property string sender
required property string title
+ required property int index
ListView.onRemove: SequentialAnimation {
PropertyAction {
@@ -76,8 +77,6 @@ ListView {
SwipeDelegate.onClicked: listView.model.remove(index)
- required property int index
-
background: Rectangle {
color: deleteLabel.SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato"
}
diff --git a/src/quickcontrols2/doc/src/includes/container-currentindex.qdocinc b/src/quickcontrols2/doc/src/includes/container-currentindex.qdocinc
new file mode 100644
index 0000000000..9fcf43e168
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/container-currentindex.qdocinc
@@ -0,0 +1,9 @@
+//! [file]
+When \1 is paired with another container such as \l \2, it is
+necessary to make a two-way binding between the
+\l {Container::}{currentIndex} property
+of each control. To do this without breaking bindings, avoid setting
+\c currentIndex directly, and instead use
+\l {Container::}{setCurrentIndex()}, for example.
+See \l {Managing the Current Index} for more information.
+//! [file]
diff --git a/src/quickcontrols2/doc/src/includes/qquickimaginestyle.qdocinc b/src/quickcontrols2/doc/src/includes/qquickimaginestyle.qdocinc
index f6fe5a970a..36297e9080 100644
--- a/src/quickcontrols2/doc/src/includes/qquickimaginestyle.qdocinc
+++ b/src/quickcontrols2/doc/src/includes/qquickimaginestyle.qdocinc
@@ -53,5 +53,7 @@
\note Due to a technical limitation, the path should not be named
\e "imagine" if it is relative to the \c qtquickcontrols2.conf file.
+ \li \c QT_QUICK_CONTROLS_IMAGINE_SMOOTH
+ \li Set to \c 1 to enable smooth scaling for 9-patch images.
\endtable
//! [env]
diff --git a/src/quickcontrols2/imagine/impl/qquickninepatchimage.cpp b/src/quickcontrols2/imagine/impl/qquickninepatchimage.cpp
index 54547cf1f2..934eb887d6 100644
--- a/src/quickcontrols2/imagine/impl/qquickninepatchimage.cpp
+++ b/src/quickcontrols2/imagine/impl/qquickninepatchimage.cpp
@@ -87,6 +87,9 @@ QList<qreal> QQuickNinePatchData::coordsForSize(qreal size) const
return coords;
}
+/*
+ Adds the 0 index coordinate if appropriate, and the one at "size".
+*/
void QQuickNinePatchData::fill(const QList<qreal> &coords, qreal size)
{
data.clear();
@@ -207,6 +210,31 @@ public:
QQuickNinePatchData yDivs;
};
+/*
+ Examines each pixel in a horizontal or vertical (if offset is equal to the image's width)
+ line, storing the start and end index ("coordinate") of each 9-patch line.
+
+ For instance, in the 7x3 (9x5 actual size) 9-patch image below, which has no horizontal
+ stretchable area, it would return {}:
+
+ +-----+
+ | |
+ +-----+
+
+ If indices 3 to 5 were marked, it would return {2, 5}:
+
+ xxx
+ +-----+
+ | |
+ +-----+
+
+ If indices 3 and 5 were marked, it would store {0, 2, 3, 4, 5, 7}:
+
+ x x
+ +-----+
+ | |
+ +-----+
+*/
static QList<qreal> readCoords(const QRgb *data, int from, int count, int offset, QRgb color)
{
int p1 = -1;
@@ -215,12 +243,16 @@ static QList<qreal> readCoords(const QRgb *data, int from, int count, int offset
int p2 = from + i * offset;
if (data[p2] == color) {
// colored pixel
- if (p1 == -1)
+ if (p1 == -1) {
+ // This is the start of a 9-patch line.
p1 = i;
+ }
} else {
// empty pixel
if (p1 != -1) {
+ // This is the end of a 9-patch line; add the start and end indices as coordinates...
coords << p1 << i;
+ // ... and reset p1 so that we can search for the next one.
p1 = -1;
}
}
@@ -228,6 +260,12 @@ static QList<qreal> readCoords(const QRgb *data, int from, int count, int offset
return coords;
}
+/*
+ Called whenever a 9-patch image is set as the image's source.
+
+ Reads the 9-patch lines from the source image and sets the
+ inset and padding properties accordingly.
+*/
void QQuickNinePatchImagePrivate::updatePatches()
{
if (ninePatch.isNull())
@@ -332,6 +370,8 @@ void QQuickNinePatchImagePrivate::updateInsets(const QList<qreal> &horizontal, c
QQuickNinePatchImage::QQuickNinePatchImage(QQuickItem *parent)
: QQuickImage(*(new QQuickNinePatchImagePrivate), parent)
{
+ Q_D(QQuickNinePatchImage);
+ d->smooth = qEnvironmentVariableIntValue("QT_QUICK_CONTROLS_IMAGINE_SMOOTH");
}
qreal QQuickNinePatchImage::topPadding() const
@@ -465,6 +505,8 @@ QSGNode *QQuickNinePatchImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNode
QSGTexture *texture = window()->createTextureFromImage(image);
patchNode->initialize(texture, sz * d->devicePixelRatio, image.size(), d->xDivs, d->yDivs, d->devicePixelRatio);
+ auto patchNodeMaterial = static_cast<QSGTextureMaterial *>(patchNode->material());
+ patchNodeMaterial->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
return patchNode;
}
diff --git a/src/quickcontrolstestutils/qtest_quickcontrols_p.h b/src/quickcontrolstestutils/qtest_quickcontrols_p.h
index ca04ee03f4..1c1ae27808 100644
--- a/src/quickcontrolstestutils/qtest_quickcontrols_p.h
+++ b/src/quickcontrolstestutils/qtest_quickcontrols_p.h
@@ -55,7 +55,7 @@
#include <QtQuickControls2/qquickstyle.h>
#include <QtQuickControls2/private/qquickstyle_p.h>
-static QStringList testStyles()
+inline QStringList testStyles()
{
// It's not enough to check if the name is empty, because since Qt 6
// we set an appropriate style for the platform if no style was specified.
@@ -66,7 +66,7 @@ static QStringList testStyles()
return QStringList(QQuickStyle::name());
}
-static int runTests(QObject *testObject, int argc, char *argv[])
+inline int runTests(QObject *testObject, int argc, char *argv[])
{
int res = 0;
QTest::qInit(testObject, argc, argv);
diff --git a/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac.mm b/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac.mm
index d376726bdb..0e2f96183f 100644
--- a/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac.mm
+++ b/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac.mm
@@ -2953,7 +2953,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
[triangleCell setState:(opt->state & State_Open) ? NSOnState : NSOffState];
// bool viewHasFocus = (w && w->hasFocus()) || (opt->state & State_HasFocus);
bool viewHasFocus = false;
- [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleDark : NSBackgroundStyleLight];
+ [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleEmphasized : NSBackgroundStyleNormal];
d->setupNSGraphicsContext(cg, NO);
diff --git a/src/quickshapes/qquickshapegenericrenderer.cpp b/src/quickshapes/qquickshapegenericrenderer.cpp
index 01869c79ad..c44ef2d4e1 100644
--- a/src/quickshapes/qquickshapegenericrenderer.cpp
+++ b/src/quickshapes/qquickshapegenericrenderer.cpp
@@ -145,8 +145,12 @@ void QQuickShapeGenericRenderer::setPath(int index, const QQuickPath *path)
void QQuickShapeGenericRenderer::setStrokeColor(int index, const QColor &color)
{
ShapePathData &d(m_sp[index]);
+ const bool wasTransparent = d.strokeColor.a == 0;
d.strokeColor = colorToColor4ub(color);
+ const bool isTransparent = d.strokeColor.a == 0;
d.syncDirty |= DirtyColor;
+ if (wasTransparent && !isTransparent)
+ d.syncDirty |= DirtyStrokeGeom;
}
void QQuickShapeGenericRenderer::setStrokeWidth(int index, qreal w)
diff --git a/src/quickshapes/qquickshapesoftwarerenderer.cpp b/src/quickshapes/qquickshapesoftwarerenderer.cpp
index dc9ccb340d..d68fc22388 100644
--- a/src/quickshapes/qquickshapesoftwarerenderer.cpp
+++ b/src/quickshapes/qquickshapesoftwarerenderer.cpp
@@ -180,10 +180,8 @@ void QQuickShapeSoftwareRenderer::endSync(bool)
void QQuickShapeSoftwareRenderer::setNode(QQuickShapeSoftwareRenderNode *node)
{
- if (m_node != node) {
- m_node = node;
- m_accDirty |= DirtyList;
- }
+ m_node = node;
+ m_accDirty |= DirtyList;
}
void QQuickShapeSoftwareRenderer::updateNode()
diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp
index ab1ac9f12c..1d89948b4d 100644
--- a/src/quicktemplates2/qquickdrawer.cpp
+++ b/src/quicktemplates2/qquickdrawer.cpp
@@ -488,6 +488,12 @@ bool QQuickDrawerPrivate::handleMove(QQuickItem *item, const QPointF &point, ulo
bool QQuickDrawerPrivate::handleRelease(QQuickItem *item, const QPointF &point, ulong timestamp)
{
+ auto cleanup = qScopeGuard([this] {
+ popupItem->setKeepMouseGrab(false);
+ popupItem->setKeepTouchGrab(false);
+ pressPoint = QPointF();
+ touchId = -1;
+ });
if (pressPoint.isNull())
return false;
if (!popupItem->keepMouseGrab() && !popupItem->keepTouchGrab()) {
@@ -547,14 +553,8 @@ bool QQuickDrawerPrivate::handleRelease(QQuickItem *item, const QPointF &point,
}
}
- bool wasGrabbed = popupItem->keepMouseGrab() || popupItem->keepTouchGrab();
- popupItem->setKeepMouseGrab(false);
- popupItem->setKeepTouchGrab(false);
-
- pressPoint = QPointF();
- touchId = -1;
-
- return wasGrabbed;
+ // the cleanup() lambda will run before return
+ return popupItem->keepMouseGrab() || popupItem->keepTouchGrab();
}
void QQuickDrawerPrivate::handleUngrab()
diff --git a/src/quicktemplates2/qquickheaderview.cpp b/src/quicktemplates2/qquickheaderview.cpp
index 3569f4c516..94d5635ad1 100644
--- a/src/quicktemplates2/qquickheaderview.cpp
+++ b/src/quicktemplates2/qquickheaderview.cpp
@@ -439,7 +439,7 @@ void QHeaderDataProxyModel::connectToModel()
if (m_model.isNull())
return;
connect(m_model, &QAbstractItemModel::headerDataChanged,
- [this](Qt::Orientation orient, int first, int last) {
+ this, [this](Qt::Orientation orient, int first, int last) {
if (orient != orientation())
return;
if (orient == Qt::Horizontal) {
diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp
index 265d5ba84a..a3492fcb54 100644
--- a/src/quicktemplates2/qquickpopup.cpp
+++ b/src/quicktemplates2/qquickpopup.cpp
@@ -445,7 +445,7 @@ bool QQuickPopupPrivate::handleTouchEvent(QQuickItem *item, QTouchEvent *event)
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
for (const QTouchEvent::TouchPoint &point : event->points()) {
- if (!acceptTouch(point))
+ if (event->type() != QEvent::TouchEnd && !acceptTouch(point))
return blockInput(item, point.position());
switch (point.state()) {
diff --git a/src/quicktemplates2/qquickpopuppositioner.cpp b/src/quicktemplates2/qquickpopuppositioner.cpp
index e247ea6556..bbdc3848cd 100644
--- a/src/quicktemplates2/qquickpopuppositioner.cpp
+++ b/src/quicktemplates2/qquickpopuppositioner.cpp
@@ -162,14 +162,18 @@ void QQuickPopupPositioner::reposition()
// if the popup doesn't fit horizontally inside the window, try flipping it around (left <-> right)
if (p->allowHorizontalFlip && (rect.left() < bounds.left() || rect.right() > bounds.right())) {
- const QRectF flipped(m_parentItem->mapToScene(QPointF(m_parentItem->width() - p->x - rect.width(), p->y)), rect.size());
+ const QPointF newTopLeft(m_parentItem->width() - p->x - rect.width(), p->y);
+ const QRectF flipped(m_parentItem->mapToItem(popupItem->parentItem(), newTopLeft),
+ rect.size());
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 (p->allowVerticalFlip && (rect.top() < bounds.top() || rect.bottom() > bounds.bottom())) {
- const QRectF flipped(m_parentItem->mapToScene(QPointF(p->x, m_parentItem->height() - p->y - rect.height())), rect.size());
+ const QPointF newTopLeft(p->x, m_parentItem->height() - p->y - rect.height());
+ const QRectF flipped(m_parentItem->mapToItem(popupItem->parentItem(), newTopLeft),
+ rect.size());
if (flipped.intersected(bounds).height() > rect.intersected(bounds).height())
rect.moveTop(flipped.top());
}
diff --git a/src/quicktemplates2/qquicksplitview.cpp b/src/quicktemplates2/qquicksplitview.cpp
index 07c5fd2baa..24e42d8258 100644
--- a/src/quicktemplates2/qquicksplitview.cpp
+++ b/src/quicktemplates2/qquicksplitview.cpp
@@ -255,7 +255,7 @@ QT_BEGIN_NAMESPACE
*/
Q_LOGGING_CATEGORY(qlcQQuickSplitView, "qt.quick.controls.splitview")
-Q_LOGGING_CATEGORY(qlcQQuickSplitViewMouse, "qt.quick.controls.splitview.mouse")
+Q_LOGGING_CATEGORY(qlcQQuickSplitViewPointer, "qt.quick.controls.splitview.pointer")
Q_LOGGING_CATEGORY(qlcQQuickSplitViewState, "qt.quick.controls.splitview.state")
void QQuickSplitViewPrivate::updateFillIndex()
@@ -930,7 +930,7 @@ void QQuickSplitViewPrivate::updateHandleVisibilities()
void QQuickSplitViewPrivate::updateHoveredHandle(QQuickItem *hoveredItem)
{
- qCDebug(qlcQQuickSplitViewMouse) << "updating hovered handle after" << hoveredItem << "was hovered";
+ qCDebug(qlcQQuickSplitViewPointer) << "updating hovered handle after" << hoveredItem << "was hovered";
const int oldHoveredHandleIndex = m_hoveredHandleIndex;
m_hoveredHandleIndex = m_handleItems.indexOf(hoveredItem);
@@ -943,16 +943,16 @@ void QQuickSplitViewPrivate::updateHoveredHandle(QQuickItem *hoveredItem)
QQuickSplitHandleAttached *oldHoveredHandleAttached = qobject_cast<QQuickSplitHandleAttached*>(
qmlAttachedPropertiesObject<QQuickSplitHandleAttached>(oldHoveredHandle, true));
QQuickSplitHandleAttachedPrivate::get(oldHoveredHandleAttached)->setHovered(false);
- qCDebug(qlcQQuickSplitViewMouse) << "handle item at index" << oldHoveredHandleIndex << "is no longer hovered";
+ qCDebug(qlcQQuickSplitViewPointer) << "handle item at index" << oldHoveredHandleIndex << "is no longer hovered";
}
if (m_hoveredHandleIndex != -1) {
QQuickSplitHandleAttached *handleAttached = qobject_cast<QQuickSplitHandleAttached*>(
qmlAttachedPropertiesObject<QQuickSplitHandleAttached>(hoveredItem, true));
QQuickSplitHandleAttachedPrivate::get(handleAttached)->setHovered(true);
- qCDebug(qlcQQuickSplitViewMouse) << "handle item at index" << m_hoveredHandleIndex << "is now hovered";
+ qCDebug(qlcQQuickSplitViewPointer) << "handle item at index" << m_hoveredHandleIndex << "is now hovered";
} else {
- qCDebug(qlcQQuickSplitViewMouse) << "either there is no hovered item or" << hoveredItem << "is not a handle";
+ qCDebug(qlcQQuickSplitViewPointer) << "either there is no hovered item or" << hoveredItem << "is not a handle";
}
}
@@ -1021,7 +1021,7 @@ void QQuickSplitViewPrivate::handlePress(const QPointF &point)
setResizing(true);
- qCDebug(qlcQQuickSplitViewMouse).nospace() << "handled press -"
+ qCDebug(qlcQQuickSplitViewPointer).nospace() << "handled press -"
<< " left/top index=" << m_pressedHandleIndex << ","
<< " size before press=" << m_leftOrTopItemSizeBeforePress << ","
<< " item=" << leftOrTopItem
@@ -1411,27 +1411,50 @@ void QQuickSplitView::hoverLeaveEvent(QHoverEvent *event)
bool QQuickSplitView::childMouseEventFilter(QQuickItem *item, QEvent *event)
{
Q_D(QQuickSplitView);
- qCDebug(qlcQQuickSplitViewMouse) << "childMouseEventFilter called with" << item << event;
-
- if (event->type() == QEvent::MouseButtonPress) {
- QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
- const QPointF point = mapFromItem(item, mouseEvent->position());
- d->handlePress(point);
-
- // Keep the mouse grab if this item belongs to the handle,
- // otherwise this event can be stolen e.g. Flickable if we're inside it.
- if (d->m_pressedHandleIndex != -1)
- item->setKeepMouseGrab(true);
- }
- else if (event->type() == QEvent::MouseButtonRelease) {
- QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
- const QPointF point = mapFromItem(item, mouseEvent->position());
- d->handleRelease(point);
- }
- else if (event->type() == QEvent::MouseMove) {
- QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
- const QPointF point = mapFromItem(item, mouseEvent->position());
- d->handleMove(point);
+ qCDebug(qlcQQuickSplitViewPointer) << "childMouseEventFilter called with" << item << event;
+
+ if (Q_LIKELY(event->isPointerEvent())) {
+ auto *pointerEvent = static_cast<QPointerEvent *>(event);
+ const auto &eventPoint = pointerEvent->points().first();
+ const QPointF point = mapFromItem(item, eventPoint.position());
+
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ d->handlePress(point);
+ // Keep the mouse grab if this item belongs to the handle,
+ // otherwise this event can be stolen e.g. Flickable if we're inside it.
+ if (d->m_pressedHandleIndex != -1)
+ item->setKeepMouseGrab(true);
+ break;
+ case QEvent::MouseButtonRelease:
+ d->handleRelease(point);
+ break;
+ case QEvent::MouseMove:
+ d->handleMove(point);
+ break;
+ case QEvent::TouchBegin:
+ if (pointerEvent->pointCount() == 1) {
+ d->handlePress(point);
+ // We filter the event on behalf of item, but we want the item
+ // to be the exclusive grabber so that we can continue to filter
+ // touch events for it.
+ if (d->m_pressedHandleIndex != -1) {
+ item->setKeepTouchGrab(true);
+ pointerEvent->setExclusiveGrabber(eventPoint, item);
+ }
+ }
+ break;
+ case QEvent::TouchEnd:
+ if (pointerEvent->pointCount() == 1)
+ d->handleRelease(point);
+ break;
+ case QEvent::TouchUpdate:
+ if (pointerEvent->pointCount() == 1)
+ d->handleMove(point);
+ break;
+ default:
+ break;
+ }
}
// If this event belongs to the handle, filter it. (d->m_pressedHandleIndex != -1) means that
diff --git a/src/quicktemplates2/qquickswipeview.cpp b/src/quicktemplates2/qquickswipeview.cpp
index 970f44b147..3277ba524f 100644
--- a/src/quicktemplates2/qquickswipeview.cpp
+++ b/src/quicktemplates2/qquickswipeview.cpp
@@ -70,6 +70,8 @@ QT_BEGIN_NAMESPACE
\l {Container::moveItem()}{move}, and \l {Container::removeItem()}{remove}
pages dynamically at run time.
+ \include container-currentindex.qdocinc {file} {SwipeView} {TabBar}
+
It is generally not advisable to add excessive amounts of pages to a
SwipeView. However, when the amount of pages grows larger, or individual
pages are relatively complex, it may be desirable to free up resources by
diff --git a/src/quicktemplates2/qquicktabbar.cpp b/src/quicktemplates2/qquicktabbar.cpp
index 68b54125ed..0297324e01 100644
--- a/src/quicktemplates2/qquicktabbar.cpp
+++ b/src/quicktemplates2/qquicktabbar.cpp
@@ -68,6 +68,8 @@ QT_BEGIN_NAMESPACE
items dynamically at run time. The items can be accessed using
\l {Container::}{itemAt()} or \l {Container::}{contentChildren}.
+ \include container-currentindex.qdocinc {file} {TabBar} {SwipeView}
+
\section2 Resizing Tabs
By default, TabBar resizes its buttons to fit the width of the control.
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 6d27e09780..d316d12588 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -664,6 +664,7 @@ QQuickWidget::QQuickWidget(QWidget *parent)
{
setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus);
+ setAttribute(Qt::WA_AcceptTouchEvents);
d_func()->init();
}
@@ -1638,9 +1639,23 @@ bool QQuickWidget::event(QEvent *e)
case QEvent::TouchBegin:
case QEvent::TouchEnd:
case QEvent::TouchUpdate:
- case QEvent::TouchCancel:
+ case QEvent::TouchCancel: {
// Touch events only have local and global positions, no need to map.
- return QCoreApplication::sendEvent(d->offscreenWindow, e);
+ bool res = QCoreApplication::sendEvent(d->offscreenWindow, e);
+ if (e->isAccepted() && e->type() == QEvent::TouchBegin) {
+ // If the TouchBegin got accepted, then make sure all points that have
+ // an exclusive grabber are also accepted so that the widget code for
+ // delivering touch events make this widget an implicit grabber of those
+ // points.
+ QPointerEvent *pointerEvent = static_cast<QPointerEvent *>(e);
+ auto deliveredPoints = pointerEvent->points();
+ for (auto &point : deliveredPoints) {
+ if (pointerEvent->exclusiveGrabber(point))
+ point.setAccepted(true);
+ }
+ }
+ return res;
+ }
case QEvent::FocusAboutToChange:
return QCoreApplication::sendEvent(d->offscreenWindow, e);