aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/plugins/qmllint/quick/quicklintplugin.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp3
-rw-r--r--src/qml/CMakeLists.txt195
-rw-r--r--src/qml/Qt6AndroidQmlMacros.cmake8
-rw-r--r--src/qml/Qt6QmlBuildInternals.cmake1
-rw-r--r--src/qml/Qt6QmlDeploySupport.cmake11
-rw-r--r--src/qml/Qt6QmlMacros.cmake428
-rw-r--r--src/qml/Qt6qt.conf.in5
-rw-r--r--src/qml/common/qv4alloca_p.h36
-rw-r--r--src/qml/common/qv4compileddata_p.h6
-rw-r--r--src/qml/common/qv4staticvalue_p.h4
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp13
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h1
-rw-r--r--src/qml/configure.cmake2
-rw-r--r--src/qml/doc/src/cmake/cmake-properties.qdoc21
-rw-r--r--src/qml/doc/src/cmake/policy/qtp0005.qdoc42
-rw-r--r--src/qml/doc/src/cmake/qt_add_qml_module.qdoc3
-rw-r--r--src/qml/doc/src/external-resources.qdoc9
-rw-r--r--src/qml/doc/src/javascript/qmlglobalobject.qdoc4
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/structure.qdoc25
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc2
-rw-r--r--src/qml/doc/src/qmlsingletons.qdoc2
-rw-r--r--src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc85
-rw-r--r--src/qml/jsapi/qjsprimitivevalue.h20
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp8
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h4
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp5
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp63
-rw-r--r--src/qml/jsruntime/qv4arrayobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4context.cpp4
-rw-r--r--src/qml/jsruntime/qv4context_p.h2
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp4
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h2
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp85
-rw-r--r--src/qml/jsruntime/qv4engine_p.h2
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp32
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h16
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit_p.h1
-rw-r--r--src/qml/jsruntime/qv4function.cpp20
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp246
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h210
-rw-r--r--src/qml/jsruntime/qv4generatorobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4generatorobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4global_p.h1
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4globalobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4jscall_p.h7
-rw-r--r--src/qml/jsruntime/qv4managed_p.h2
-rw-r--r--src/qml/jsruntime/qv4mapobject.cpp26
-rw-r--r--src/qml/jsruntime/qv4mapobject_p.h8
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp4
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h2
-rw-r--r--src/qml/jsruntime/qv4promiseobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4promiseobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4proxy.cpp39
-rw-r--r--src/qml/jsruntime/qv4proxy_p.h17
-rw-r--r--src/qml/jsruntime/qv4qmetaobjectwrapper.cpp71
-rw-r--r--src/qml/jsruntime/qv4qmetaobjectwrapper_p.h72
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp119
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h9
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp60
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp136
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4setobject.cpp18
-rw-r--r--src/qml/jsruntime/qv4setobject_p.h8
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4symbol.cpp4
-rw-r--r--src/qml/jsruntime/qv4symbol_p.h2
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp14
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h4
-rw-r--r--src/qml/jsruntime/qv4urlobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4urlobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4value_p.h5
-rw-r--r--src/qml/jsruntime/qv4vtable_p.h77
-rw-r--r--src/qml/parser/qqmljs.g8
-rw-r--r--src/qml/parser/qqmljsast_p.h1
-rw-r--r--src/qml/parser/qqmljslexer.cpp55
-rw-r--r--src/qml/parser/qqmljslexer_p.h2
-rw-r--r--src/qml/qml/ftw/qqmlnullablevalue_p.h2
-rw-r--r--src/qml/qml/qqml.cpp10
-rw-r--r--src/qml/qml/qqmlbinding.cpp3
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp5
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions.cpp72
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions_p.h16
-rw-r--r--src/qml/qml/qqmlcontextdata_p.h4
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp5
-rw-r--r--src/qml/qml/qqmlengine.cpp65
-rw-r--r--src/qml/qml/qqmlglobal.cpp8
-rw-r--r--src/qml/qml/qqmlglobal_p.h1
-rw-r--r--src/qml/qml/qqmlimport.cpp5
-rw-r--r--src/qml/qml/qqmlirloader.cpp2
-rw-r--r--src/qml/qml/qqmllocale_p.h23
-rw-r--r--src/qml/qml/qqmlloggingcategorybase_p.h47
-rw-r--r--src/qml/qml/qqmlmetamoduleregistration.cpp26
-rw-r--r--src/qml/qml/qqmlplatform.cpp7
-rw-r--r--src/qml/qml/qqmlplatform_p.h1
-rw-r--r--src/qml/qml/qqmlproperty.h1
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp20
-rw-r--r--src/qml/qml/qqmlpropertydata_p.h13
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp225
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h86
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h14
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp45
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h8
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp2
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp2
-rw-r--r--src/qml/qqmlbuiltins_p.h237
-rw-r--r--src/qml/types/qqmlbind.cpp6
-rw-r--r--src/qml/types/qqmlbind_p.h4
-rw-r--r--src/qml/types/qqmlconnections.cpp5
-rw-r--r--src/qml/types/qqmlconnections_p.h6
-rw-r--r--src/qml/types/qqmllocaleenums_p.h48
-rw-r--r--src/qml/types/qqmlloggingcategory.cpp (renamed from src/qml/qml/qqmlloggingcategory.cpp)15
-rw-r--r--src/qml/types/qqmlloggingcategory_p.h (renamed from src/qml/qml/qqmlloggingcategory_p.h)19
-rw-r--r--src/qml/types/qqmltimer_p.h8
-rw-r--r--src/qmlcompiler/CMakeLists.txt2
-rw-r--r--src/qmlcompiler/qdeferredpointer_p.h8
-rw-r--r--src/qmlcompiler/qqmljsbasicblocks.cpp12
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp28
-rw-r--r--src/qmlcompiler/qqmljscompiler.cpp29
-rw-r--r--src/qmlcompiler/qqmljscompiler_p.h12
-rw-r--r--src/qmlcompiler/qqmljscompilerstats.cpp188
-rw-r--r--src/qmlcompiler/qqmljscompilerstats_p.h92
-rw-r--r--src/qmlcompiler/qqmljscompilerstatsreporter.cpp118
-rw-r--r--src/qmlcompiler/qqmljscompilerstatsreporter_p.h57
-rw-r--r--src/qmlcompiler/qqmljsimporter.cpp38
-rw-r--r--src/qmlcompiler/qqmljslinter.cpp2
-rw-r--r--src/qmlcompiler/qqmljsoptimizations.cpp13
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp21
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h13
-rw-r--r--src/qmlcompiler/qqmljsutils_p.h21
-rw-r--r--src/qmldom/qqmldomastcreator.cpp500
-rw-r--r--src/qmldom/qqmldomastcreator_p.h53
-rw-r--r--src/qmldom/qqmldomcomments.cpp9
-rw-r--r--src/qmldom/qqmldomcomments_p.h11
-rw-r--r--src/qmldom/qqmldomconstants_p.h5
-rw-r--r--src/qmldom/qqmldomelements.cpp15
-rw-r--r--src/qmldom/qqmldomelements_p.h11
-rw-r--r--src/qmldom/qqmldomexternalitems_p.h5
-rw-r--r--src/qmldom/qqmldomoutwriter.cpp10
-rw-r--r--src/qmldom/qqmldomreformatter.cpp46
-rw-r--r--src/qmldom/qqmldomreformatter_p.h3
-rw-r--r--src/qmldom/qqmldomscriptelements.cpp3
-rw-r--r--src/qmldom/qqmldomscriptelements_p.h18
-rw-r--r--src/qmldom/qqmldomtop.cpp113
-rw-r--r--src/qmldom/qqmldomtop_p.h9
-rw-r--r--src/qmlintegration/qqmlintegration.h29
-rw-r--r--src/qmlls/CMakeLists.txt4
-rw-r--r--src/qmlls/qdochtmlparser.cpp119
-rw-r--r--src/qmlls/qdochtmlparser_p.h30
-rw-r--r--src/qmlls/qlanguageserver.cpp10
-rw-r--r--src/qmlls/qlanguageserver_p.h3
-rw-r--r--src/qmlls/qqmlbasemodule_p.h26
-rw-r--r--src/qmlls/qqmlcodemodel.cpp33
-rw-r--r--src/qmlls/qqmlcodemodel_p.h22
-rw-r--r--src/qmlls/qqmlcompletionsupport.cpp11
-rw-r--r--src/qmlls/qqmlcompletionsupport_p.h3
-rw-r--r--src/qmlls/qqmlfindusagessupport.cpp6
-rw-r--r--src/qmlls/qqmlformatting.cpp6
-rw-r--r--src/qmlls/qqmlgotodefinitionsupport.cpp2
-rw-r--r--src/qmlls/qqmlgototypedefinitionsupport.cpp2
-rw-r--r--src/qmlls/qqmlhighlightsupport.cpp212
-rw-r--r--src/qmlls/qqmlhighlightsupport_p.h96
-rw-r--r--src/qmlls/qqmlhover.cpp55
-rw-r--r--src/qmlls/qqmlhover_p.h6
-rw-r--r--src/qmlls/qqmllanguageserver.cpp4
-rw-r--r--src/qmlls/qqmllanguageserver_p.h2
-rw-r--r--src/qmlls/qqmllscompletion.cpp15
-rw-r--r--src/qmlls/qqmllscompletion_p.h6
-rw-r--r--src/qmlls/qqmllshelpplugininterface.cpp4
-rw-r--r--src/qmlls/qqmllshelpplugininterface_p.h64
-rw-r--r--src/qmlls/qqmllshelputils.cpp254
-rw-r--r--src/qmlls/qqmllshelputils_p.h60
-rw-r--r--src/qmlls/qqmllsutils.cpp598
-rw-r--r--src/qmlls/qqmllsutils_p.h220
-rw-r--r--src/qmlls/qqmlrenamesymbolsupport.cpp19
-rw-r--r--src/qmlls/qqmlsemantictokens.cpp771
-rw-r--r--src/qmlls/qqmlsemantictokens_p.h131
-rw-r--r--src/qmlmodels/CMakeLists.txt2
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp46
-rw-r--r--src/qmlmodels/qqmldmabstractitemmodeldata_p.h11
-rw-r--r--src/qmltest/doc/snippets/testApp/CMakeLists.txt2
-rw-r--r--src/qmltest/doc/snippets/testApp/MyModule/CMakeLists.txt2
-rw-r--r--src/qmltest/doc/snippets/testApp/tests/CMakeLists.txt2
-rw-r--r--src/qmltest/doc/snippets/testApp/tests/main.cpp2
-rw-r--r--src/qmltest/doc/snippets/testApp/tests/setup.cpp2
-rw-r--r--src/qmltest/doc/snippets/testApp/tests/setup.h2
-rw-r--r--src/qmltest/quicktest.cpp12
-rw-r--r--src/qmltoolingsettings/qqmltoolingsettings.cpp2
-rw-r--r--src/qmltyperegistrar/qmetatypesjsonprocessor.cpp46
-rw-r--r--src/qmltyperegistrar/qmetatypesjsonprocessor_p.h29
-rw-r--r--src/qmltyperegistrar/qqmltyperegistrar.cpp34
-rw-r--r--src/qmltyperegistrar/qqmltyperegistrar_p.h2
-rw-r--r--src/qmltyperegistrar/qqmltyperegistrarconstants_p.h1
-rw-r--r--src/qmltyperegistrar/qqmltypesclassdescription.cpp97
-rw-r--r--src/qmltyperegistrar/qqmltypesclassdescription_p.h8
-rw-r--r--src/qmltyperegistrar/qqmltypescreator.cpp6
-rw-r--r--src/qmltyperegistrar/qqmltypescreator_p.h2
-rw-r--r--src/qmlworkerscript/CMakeLists.txt2
-rw-r--r--src/quick/CMakeLists.txt47
-rw-r--r--src/quick/accessible/qaccessiblequickitem.cpp27
-rw-r--r--src/quick/doc/qtquick.qdocconf3
-rw-r--r--src/quick/doc/snippets/qml/font.qml22
-rw-r--r--src/quick/doc/snippets/qml/windowPalette.qml2
-rw-r--r--src/quick/doc/src/qmltypereference.qdoc14
-rw-r--r--src/quick/doc/src/qtquick.qdoc7
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp109
-rw-r--r--src/quick/items/qquickaccessibleattached_p.h42
-rw-r--r--src/quick/items/qquickborderimage.cpp26
-rw-r--r--src/quick/items/qquickdrag.cpp2
-rw-r--r--src/quick/items/qquickimage.cpp79
-rw-r--r--src/quick/items/qquickimagebase.cpp98
-rw-r--r--src/quick/items/qquickimagebase_p.h5
-rw-r--r--src/quick/items/qquickimagebase_p_p.h11
-rw-r--r--src/quick/items/qquickitem.cpp34
-rw-r--r--src/quick/items/qquickitem_p.h2
-rw-r--r--src/quick/items/qquickmousearea.cpp1
-rw-r--r--src/quick/items/qquickpalettecolorprovider.cpp1
-rw-r--r--src/quick/items/qquickselectable_p.h2
-rw-r--r--src/quick/items/qquicktableview.cpp671
-rw-r--r--src/quick/items/qquicktableview_p.h8
-rw-r--r--src/quick/items/qquicktableview_p_p.h119
-rw-r--r--src/quick/items/qquicktext.cpp149
-rw-r--r--src/quick/items/qquicktext_p_p.h7
-rw-r--r--src/quick/items/qquicktextdocument.cpp30
-rw-r--r--src/quick/items/qquicktextedit.cpp15
-rw-r--r--src/quick/items/qquicktextinput.cpp14
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp14
-rw-r--r--src/quick/items/qquickwindow.cpp51
-rw-r--r--src/quick/items/qquickwindow_p.h1
-rw-r--r--src/quick/items/qquickwindowcontainer.cpp1
-rw-r--r--src/quick/items/qquickwindowmodule.cpp31
-rw-r--r--src/quick/items/qquickwindowmodule_p_p.h2
-rw-r--r--src/quick/jar/CMakeLists.txt11
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtAbstractItemModel.java105
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtAbstractItemModelProxy.java35
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtAbstractListModel.java30
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtModelIndex.java42
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQmlComponent.java205
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQmlStatus.java49
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQmlStatusChangeListener.java17
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQuickView.java166
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc40
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtSignalListener.java17
-rw-r--r--src/quick/platform/android/qandroiditemmodelproxy.cpp379
-rw-r--r--src/quick/platform/android/qandroiditemmodelproxy_p.h191
-rw-r--r--src/quick/platform/android/qandroidmodelindexproxy.cpp103
-rw-r--r--src/quick/platform/android/qandroidmodelindexproxy_p.h56
-rw-r--r--src/quick/platform/android/qandroidquickviewembedding.cpp312
-rw-r--r--src/quick/platform/android/qandroidquickviewembedding_p.h40
-rw-r--r--src/quick/platform/android/qandroidtypeconverter_p.h99
-rw-r--r--src/quick/platform/android/qandroidtypes_p.h40
-rw-r--r--src/quick/platform/android/qandroidviewsignalmanager.cpp77
-rw-r--r--src/quick/platform/android/qandroidviewsignalmanager_p.h57
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp10
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h2
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.cpp9
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterialshader.cpp23
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterialshader.h11
-rw-r--r--src/quick/scenegraph/coreapi/qsgtexture.cpp4
-rw-r--r--src/quick/scenegraph/qsgcurvefillnode.cpp1
-rw-r--r--src/quick/scenegraph/qsgcurvefillnode_p.cpp240
-rw-r--r--src/quick/scenegraph/qsgcurvefillnode_p.h123
-rw-r--r--src/quick/scenegraph/qsgcurvefillnode_p_p.h13
-rw-r--r--src/quick/scenegraph/qsgcurveprocessor.cpp2
-rw-r--r--src/quick/scenegraph/qsgrhisupport.cpp2
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp28
-rw-r--r--src/quick/scenegraph/shaders_ng/shapecurve.frag36
-rw-r--r--src/quick/scenegraph/shaders_ng/shapecurve.vert23
-rw-r--r--src/quick/scenegraph/util/qsgtransform.cpp10
-rw-r--r--src/quick/scenegraph/util/qsgtransform_p.h105
-rw-r--r--src/quick/util/qminimalflatset_p.h149
-rw-r--r--src/quick/util/qquickdeliveryagent.cpp2
-rw-r--r--src/quick/util/qquickpath.cpp294
-rw-r--r--src/quick/util/qquickpath_p.h78
-rw-r--r--src/quick/util/qquickpixmap_p.h1
-rw-r--r--src/quick/util/qquickpixmapcache.cpp13
-rw-r--r--src/quick/util/qquickstyledtext.cpp5
-rw-r--r--src/quick/util/qquickstyledtext_p.h8
-rw-r--r--src/quick/util/qquickvaluetypes.cpp199
-rw-r--r--src/quick/util/qquickvaluetypes_p.h38
-rw-r--r--src/quickcontrols/CMakeLists.txt5
-rw-r--r--src/quickcontrols/basic/ComboBox.qml1
-rw-r--r--src/quickcontrols/configure.cmake8
-rw-r--r--src/quickcontrols/doc/images/qtquickcontrols-menu-native.pngbin0 -> 7479 bytes
-rw-r--r--src/quickcontrols/doc/images/qtquickcontrols-menu.pngbin3629 -> 12317 bytes
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-busyindicator-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-button-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-checkbox-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-checkdelegate-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-combobox-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-delaybutton-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-dial-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-frame-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-groupbox-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-label-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-menu-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-menubar-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-menuseparator-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-pageindicator-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-pane-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-popup-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-progressbar-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-radiobutton-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-radiodelegate-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-rangeslider-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-scrollbar-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-scrollindicator-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-scrollview-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-slider-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-spinbox-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-splitview-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-stackview-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-swipedelegate-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-swipeview-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-switch-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-switchdelegate-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-tabbar-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-textarea-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-textfield-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-toolbar-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-toolbutton-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-toolseparator-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-tumbler-custom.qml2
-rw-r--r--src/quickcontrols/doc/src/includes/qquickheaderview.qdocinc18
-rw-r--r--src/quickcontrols/doc/src/includes/qquickmenu.qdocinc4
-rw-r--r--src/quickcontrols/doc/src/qtquickcontrols-customize.qdoc10
-rw-r--r--src/quickcontrols/fluentwinui3/ApplicationWindow.qml12
-rw-r--r--src/quickcontrols/fluentwinui3/Button.qml59
-rw-r--r--src/quickcontrols/fluentwinui3/CMakeLists.txt69
-rw-r--r--src/quickcontrols/fluentwinui3/CheckBox.qml61
-rw-r--r--src/quickcontrols/fluentwinui3/Config.qml9920
-rw-r--r--src/quickcontrols/fluentwinui3/ProgressBar.qml117
-rw-r--r--src/quickcontrols/fluentwinui3/RadioButton.qml59
-rw-r--r--src/quickcontrols/fluentwinui3/RangeSlider.qml197
-rw-r--r--src/quickcontrols/fluentwinui3/Slider.qml144
-rw-r--r--src/quickcontrols/fluentwinui3/StyleImage.qml54
-rw-r--r--src/quickcontrols/fluentwinui3/Switch.qml81
-rw-r--r--src/quickcontrols/fluentwinui3/TextArea.qml73
-rw-r--r--src/quickcontrols/fluentwinui3/TextField.qml73
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled.pngbin0 -> 183 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@2x.pngbin0 -> 268 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@3x.pngbin0 -> 352 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@2x.pngbin0 -> 739 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@3x.pngbin0 -> 1258 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed.pngbin0 -> 249 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@2x.pngbin0 -> 467 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@3x.pngbin0 -> 614 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked.pngbin0 -> 303 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked@2x.pngbin0 -> 735 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked@3x.pngbin0 -> 1151 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-disabled.pngbin0 -> 206 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@2x.pngbin0 -> 360 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@3x.pngbin0 -> 478 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-hovered.pngbin0 -> 296 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@2x.pngbin0 -> 589 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@3x.pngbin0 -> 1019 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-pressed.pngbin0 -> 206 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@2x.pngbin0 -> 361 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@3x.pngbin0 -> 486 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background.pngbin0 -> 303 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background@2x.pngbin0 -> 666 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background@3x.pngbin0 -> 1148 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled.pngbin0 -> 237 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@2x.pngbin0 -> 351 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@3x.pngbin0 -> 452 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered.pngbin0 -> 270 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@2x.pngbin0 -> 389 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@3x.pngbin0 -> 511 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed.pngbin0 -> 270 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@2x.pngbin0 -> 420 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@3x.pngbin0 -> 530 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked.pngbin0 -> 234 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@2x.pngbin0 -> 360 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@3x.pngbin0 -> 455 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@2x.pngbin0 -> 260 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@3x.pngbin0 -> 328 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled.pngbin0 -> 201 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@2x.pngbin0 -> 286 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@3x.pngbin0 -> 393 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@2x.pngbin0 -> 298 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@3x.pngbin0 -> 388 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@2x.pngbin0 -> 289 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@3x.pngbin0 -> 409 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@2x.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@3x.pngbin0 -> 414 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked.pngbin0 -> 196 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@2x.pngbin0 -> 274 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@3x.pngbin0 -> 342 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed.pngbin0 -> 205 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@2x.pngbin0 -> 314 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@3x.pngbin0 -> 409 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@2x.pngbin0 -> 394 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@3x.pngbin0 -> 546 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled.pngbin0 -> 182 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@2x.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@3x.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered.pngbin0 -> 321 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@2x.pngbin0 -> 794 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@3x.pngbin0 -> 1384 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed.pngbin0 -> 263 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@2x.pngbin0 -> 492 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@3x.pngbin0 -> 612 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked.pngbin0 -> 311 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@2x.pngbin0 -> 722 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@3x.pngbin0 -> 1163 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled.pngbin0 -> 91 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@2x.pngbin0 -> 104 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@3x.pngbin0 -> 110 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered.pngbin0 -> 170 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@2x.pngbin0 -> 251 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@3x.pngbin0 -> 322 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed.pngbin0 -> 172 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@2x.pngbin0 -> 239 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@3x.pngbin0 -> 321 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled-indeterminate.pngbin0 -> 82 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled-indeterminate@2x.pngbin0 -> 99 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled-indeterminate@3x.pngbin0 -> 111 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled.pngbin0 -> 82 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@2x.pngbin0 -> 99 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@3x.pngbin0 -> 111 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-indeterminate.pngbin0 -> 82 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-indeterminate@2x.pngbin0 -> 98 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-indeterminate@3x.pngbin0 -> 111 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove.pngbin0 -> 82 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@2x.pngbin0 -> 98 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@3x.pngbin0 -> 111 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled.pngbin0 -> 348 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@2x.pngbin0 -> 545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@3x.pngbin0 -> 700 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@2x.pngbin0 -> 1198 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@3x.pngbin0 -> 1675 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed.pngbin0 -> 565 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@2x.pngbin0 -> 1044 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@3x.pngbin0 -> 1476 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked.pngbin0 -> 449 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@2x.pngbin0 -> 809 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@3x.pngbin0 -> 1109 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled.pngbin0 -> 334 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@2x.pngbin0 -> 516 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@3x.pngbin0 -> 691 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered.pngbin0 -> 395 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@2x.pngbin0 -> 600 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@3x.pngbin0 -> 792 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed.pngbin0 -> 485 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@2x.pngbin0 -> 815 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@3x.pngbin0 -> 1057 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator.pngbin0 -> 468 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@2x.pngbin0 -> 713 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@3x.pngbin0 -> 924 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@2x.pngbin0 -> 698 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@3x.pngbin0 -> 935 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@2x.pngbin0 -> 698 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@3x.pngbin0 -> 935 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered.pngbin0 -> 493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@2x.pngbin0 -> 875 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@3x.pngbin0 -> 1283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle.pngbin0 -> 493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@2x.pngbin0 -> 875 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@3x.pngbin0 -> 1283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@3x.pngbin0 -> 216 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@2x.pngbin0 -> 183 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@2x.pngbin0 -> 183 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@2x.pngbin0 -> 183 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@2x.pngbin0 -> 698 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@3x.pngbin0 -> 935 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@2x.pngbin0 -> 698 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@3x.pngbin0 -> 935 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered.pngbin0 -> 493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@2x.pngbin0 -> 875 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@3x.pngbin0 -> 1283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle.pngbin0 -> 493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@2x.pngbin0 -> 875 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@3x.pngbin0 -> 1283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-disabled.pngbin0 -> 124 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-disabled@2x.pngbin0 -> 174 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-disabled@3x.pngbin0 -> 214 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-handle-pressed.pngbin0 -> 139 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-handle-pressed@2x.pngbin0 -> 202 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-handle-pressed@3x.pngbin0 -> 237 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-hovered.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-hovered@2x.pngbin0 -> 187 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-hovered@3x.pngbin0 -> 214 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-track.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-track@2x.pngbin0 -> 187 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-track@3x.pngbin0 -> 214 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@2x.pngbin0 -> 172 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@3x.pngbin0 -> 217 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered.pngbin0 -> 130 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@2x.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@3x.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed.pngbin0 -> 130 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@2x.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@3x.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove.pngbin0 -> 130 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove@2x.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove@3x.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@2x.pngbin0 -> 698 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@3x.pngbin0 -> 935 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered.pngbin0 -> 493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@2x.pngbin0 -> 875 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@3x.pngbin0 -> 1283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@2x.pngbin0 -> 698 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@3x.pngbin0 -> 935 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle.pngbin0 -> 493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle@2x.pngbin0 -> 875 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle@3x.pngbin0 -> 1283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-track-disabled.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-track-disabled@2x.pngbin0 -> 175 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-track-disabled@3x.pngbin0 -> 217 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-track-hovered.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-track-hovered@2x.pngbin0 -> 175 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-track-hovered@3x.pngbin0 -> 218 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-track-pressed.pngbin0 -> 142 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-track-pressed@2x.pngbin0 -> 202 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-track-pressed@3x.pngbin0 -> 236 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-track.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-track@2x.pngbin0 -> 175 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-track@3x.pngbin0 -> 218 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled.pngbin0 -> 270 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@2x.pngbin0 -> 390 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@3x.pngbin0 -> 508 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered.pngbin0 -> 317 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@2x.pngbin0 -> 470 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@3x.pngbin0 -> 605 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed.pngbin0 -> 326 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@2x.pngbin0 -> 489 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@3x.pngbin0 -> 628 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@2x.pngbin0 -> 416 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@3x.pngbin0 -> 542 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@2x.pngbin0 -> 530 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@3x.pngbin0 -> 702 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered.pngbin0 -> 376 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@2x.pngbin0 -> 620 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@3x.pngbin0 -> 795 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed.pngbin0 -> 371 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@2x.pngbin0 -> 592 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@3x.pngbin0 -> 774 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background.pngbin0 -> 515 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@2x.pngbin0 -> 810 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@3x.pngbin0 -> 1036 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled.pngbin0 -> 281 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@2x.pngbin0 -> 555 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@3x.pngbin0 -> 806 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered.pngbin0 -> 380 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@2x.pngbin0 -> 696 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@3x.pngbin0 -> 1021 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed.pngbin0 -> 384 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@2x.pngbin0 -> 710 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@3x.pngbin0 -> 1058 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked.pngbin0 -> 333 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@2x.pngbin0 -> 610 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@3x.pngbin0 -> 919 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled.pngbin0 -> 204 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@2x.pngbin0 -> 282 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@3x.pngbin0 -> 369 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@2x.pngbin0 -> 299 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@3x.pngbin0 -> 391 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@2x.pngbin0 -> 303 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@3x.pngbin0 -> 396 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle@2x.pngbin0 -> 274 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle@3x.pngbin0 -> 349 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled.pngbin0 -> 417 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@2x.pngbin0 -> 977 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@3x.pngbin0 -> 1557 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused.pngbin0 -> 460 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@2x.pngbin0 -> 1106 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@3x.pngbin0 -> 1742 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered.pngbin0 -> 417 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@2x.pngbin0 -> 977 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@3x.pngbin0 -> 1557 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background.pngbin0 -> 417 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background@2x.pngbin0 -> 977 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background@3x.pngbin0 -> 1557 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled.pngbin0 -> 402 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@2x.pngbin0 -> 849 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@3x.pngbin0 -> 1316 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@2x.pngbin0 -> 765 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@3x.pngbin0 -> 1141 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered.pngbin0 -> 372 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@2x.pngbin0 -> 822 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@3x.pngbin0 -> 1215 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background.pngbin0 -> 387 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background@2x.pngbin0 -> 849 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background@3x.pngbin0 -> 1291 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/impl/CMakeLists.txt28
-rw-r--r--src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke.cpp52
-rw-r--r--src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke_p.h39
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@2x.pngbin0 -> 291 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@3x.pngbin0 -> 351 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered.pngbin0 -> 439 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@2x.pngbin0 -> 1056 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@3x.pngbin0 -> 1781 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed.pngbin0 -> 282 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@2x.pngbin0 -> 493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@3x.pngbin0 -> 698 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked.pngbin0 -> 410 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked@2x.pngbin0 -> 997 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked@3x.pngbin0 -> 1848 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-disabled.pngbin0 -> 223 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-disabled@2x.pngbin0 -> 411 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-disabled@3x.pngbin0 -> 543 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-hovered.pngbin0 -> 333 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-hovered@2x.pngbin0 -> 890 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-hovered@3x.pngbin0 -> 1303 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-pressed.pngbin0 -> 223 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-pressed@2x.pngbin0 -> 411 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-pressed@3x.pngbin0 -> 543 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background.pngbin0 -> 399 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background@2x.pngbin0 -> 848 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background@3x.pngbin0 -> 1545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@2x.pngbin0 -> 355 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@3x.pngbin0 -> 455 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered.pngbin0 -> 261 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@2x.pngbin0 -> 382 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@3x.pngbin0 -> 506 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed.pngbin0 -> 259 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@2x.pngbin0 -> 412 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@3x.pngbin0 -> 514 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked.pngbin0 -> 248 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@2x.pngbin0 -> 368 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@3x.pngbin0 -> 460 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@2x.pngbin0 -> 262 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@3x.pngbin0 -> 331 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled.pngbin0 -> 201 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@2x.pngbin0 -> 295 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@3x.pngbin0 -> 395 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked.pngbin0 -> 207 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@2x.pngbin0 -> 298 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@3x.pngbin0 -> 395 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered.pngbin0 -> 209 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@2x.pngbin0 -> 310 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@3x.pngbin0 -> 430 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed.pngbin0 -> 211 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@2x.pngbin0 -> 327 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@3x.pngbin0 -> 396 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked.pngbin0 -> 198 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@2x.pngbin0 -> 282 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@3x.pngbin0 -> 351 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed.pngbin0 -> 205 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@2x.pngbin0 -> 323 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@3x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator.pngbin0 -> 205 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@2x.pngbin0 -> 325 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@3x.pngbin0 -> 448 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled.pngbin0 -> 182 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@2x.pngbin0 -> 288 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@3x.pngbin0 -> 349 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered.pngbin0 -> 432 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@2x.pngbin0 -> 1045 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@3x.pngbin0 -> 1751 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed.pngbin0 -> 281 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@2x.pngbin0 -> 492 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@3x.pngbin0 -> 694 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked.pngbin0 -> 398 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@2x.pngbin0 -> 994 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@3x.pngbin0 -> 1846 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled.pngbin0 -> 91 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@2x.pngbin0 -> 104 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@3x.pngbin0 -> 110 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered.pngbin0 -> 172 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@2x.pngbin0 -> 238 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@3x.pngbin0 -> 315 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@2x.pngbin0 -> 223 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@3x.pngbin0 -> 290 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled-indeterminate.pngbin0 -> 81 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled-indeterminate@2x.pngbin0 -> 97 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled-indeterminate@3x.pngbin0 -> 112 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled.pngbin0 -> 81 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@2x.pngbin0 -> 97 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@3x.pngbin0 -> 112 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove-indeterminate.pngbin0 -> 81 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove-indeterminate@2x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove-indeterminate@3x.pngbin0 -> 113 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove.pngbin0 -> 81 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove@2x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove@3x.pngbin0 -> 113 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@2x.pngbin0 -> 556 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@3x.pngbin0 -> 696 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered.pngbin0 -> 613 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@2x.pngbin0 -> 1182 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@3x.pngbin0 -> 1723 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed.pngbin0 -> 530 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@2x.pngbin0 -> 993 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@3x.pngbin0 -> 1363 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked.pngbin0 -> 490 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@2x.pngbin0 -> 920 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@3x.pngbin0 -> 1293 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled.pngbin0 -> 341 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@2x.pngbin0 -> 532 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@3x.pngbin0 -> 700 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered.pngbin0 -> 388 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@2x.pngbin0 -> 619 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@3x.pngbin0 -> 793 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed.pngbin0 -> 412 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@2x.pngbin0 -> 710 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@3x.pngbin0 -> 953 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator.pngbin0 -> 397 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@2x.pngbin0 -> 637 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@3x.pngbin0 -> 820 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@2x.pngbin0 -> 590 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@3x.pngbin0 -> 780 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@2x.pngbin0 -> 590 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@3x.pngbin0 -> 780 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered.pngbin0 -> 513 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@2x.pngbin0 -> 1086 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@3x.pngbin0 -> 1545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle.pngbin0 -> 513 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@2x.pngbin0 -> 1086 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@3x.pngbin0 -> 1545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@2x.pngbin0 -> 174 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@3x.pngbin0 -> 212 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@2x.pngbin0 -> 180 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@2x.pngbin0 -> 180 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@2x.pngbin0 -> 180 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@2x.pngbin0 -> 590 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@3x.pngbin0 -> 780 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@2x.pngbin0 -> 590 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@3x.pngbin0 -> 780 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered.pngbin0 -> 513 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@2x.pngbin0 -> 1086 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@3x.pngbin0 -> 1545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle.pngbin0 -> 513 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@2x.pngbin0 -> 1086 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@3x.pngbin0 -> 1545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-track-disabled.pngbin0 -> 124 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-track-disabled@2x.pngbin0 -> 178 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-track-disabled@3x.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-track-handle-pressed.pngbin0 -> 136 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-track-handle-pressed@2x.pngbin0 -> 191 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-track-handle-pressed@3x.pngbin0 -> 236 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-track-hovered.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-track-hovered@2x.pngbin0 -> 190 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-track-hovered@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-track.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-track@2x.pngbin0 -> 190 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-track@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@2x.pngbin0 -> 179 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@3x.pngbin0 -> 214 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@3x.pngbin0 -> 234 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@3x.pngbin0 -> 234 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove@3x.pngbin0 -> 234 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@2x.pngbin0 -> 590 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@3x.pngbin0 -> 780 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered.pngbin0 -> 513 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@2x.pngbin0 -> 1086 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@3x.pngbin0 -> 1545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@2x.pngbin0 -> 590 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@3x.pngbin0 -> 780 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle.pngbin0 -> 513 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle@2x.pngbin0 -> 1086 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle@3x.pngbin0 -> 1545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-track-disabled.pngbin0 -> 126 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-track-disabled@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-track-disabled@3x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-track-hovered.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-track-hovered@2x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-track-hovered@3x.pngbin0 -> 230 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-track-pressed.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-track-pressed@2x.pngbin0 -> 189 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-track-pressed@3x.pngbin0 -> 236 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-track.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-track@2x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-track@3x.pngbin0 -> 230 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled.pngbin0 -> 275 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@2x.pngbin0 -> 402 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@3x.pngbin0 -> 516 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered.pngbin0 -> 303 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@2x.pngbin0 -> 459 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@3x.pngbin0 -> 586 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed.pngbin0 -> 303 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@2x.pngbin0 -> 480 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@3x.pngbin0 -> 600 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@2x.pngbin0 -> 425 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@3x.pngbin0 -> 556 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@2x.pngbin0 -> 530 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@3x.pngbin0 -> 702 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered.pngbin0 -> 376 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@2x.pngbin0 -> 591 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@3x.pngbin0 -> 788 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed.pngbin0 -> 410 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@2x.pngbin0 -> 646 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@3x.pngbin0 -> 820 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background.pngbin0 -> 390 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background@2x.pngbin0 -> 626 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background@3x.pngbin0 -> 804 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled.pngbin0 -> 250 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@2x.pngbin0 -> 716 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@3x.pngbin0 -> 1115 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered.pngbin0 -> 397 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@2x.pngbin0 -> 816 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@3x.pngbin0 -> 1180 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed.pngbin0 -> 407 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@2x.pngbin0 -> 806 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@3x.pngbin0 -> 1215 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked.pngbin0 -> 250 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@2x.pngbin0 -> 716 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@3x.pngbin0 -> 1115 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@2x.pngbin0 -> 270 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@3x.pngbin0 -> 376 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@2x.pngbin0 -> 305 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@3x.pngbin0 -> 397 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@2x.pngbin0 -> 307 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@3x.pngbin0 -> 400 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle.pngbin0 -> 196 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle@2x.pngbin0 -> 275 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle@3x.pngbin0 -> 371 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled.pngbin0 -> 528 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@2x.pngbin0 -> 1231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@3x.pngbin0 -> 1957 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-focused.pngbin0 -> 485 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@2x.pngbin0 -> 1114 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@3x.pngbin0 -> 1803 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered.pngbin0 -> 528 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@2x.pngbin0 -> 1231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@3x.pngbin0 -> 1957 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background.pngbin0 -> 528 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background@2x.pngbin0 -> 1231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background@3x.pngbin0 -> 1957 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled.pngbin0 -> 491 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@2x.pngbin0 -> 1059 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@3x.pngbin0 -> 1671 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-focused.pngbin0 -> 451 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@2x.pngbin0 -> 954 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@3x.pngbin0 -> 1492 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered.pngbin0 -> 487 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@2x.pngbin0 -> 1060 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@3x.pngbin0 -> 1657 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background.pngbin0 -> 498 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background@2x.pngbin0 -> 1046 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background@3x.pngbin0 -> 1691 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/qquickfluentwinui3theme.cpp133
-rw-r--r--src/quickcontrols/fluentwinui3/qquickfluentwinui3theme_p.h33
-rw-r--r--src/quickcontrols/fluentwinui3/qtquickcontrols2fluentwinui3styleplugin.cpp56
-rw-r--r--src/quickcontrols/fusion/ComboBox.qml1
-rw-r--r--src/quickcontrols/ios/CMakeLists.txt4
-rw-r--r--src/quickcontrols/macos/CMakeLists.txt16
-rw-r--r--src/quickcontrols/macos/Menu.qml79
-rw-r--r--src/quickcontrols/macos/MenuBar.qml35
-rw-r--r--src/quickcontrols/macos/MenuBarItem.qml46
-rw-r--r--src/quickcontrols/macos/MenuItem.qml75
-rw-r--r--src/quickcontrols/macos/MenuSeparator.qml24
-rw-r--r--src/quickcontrols/macos/ScrollIndicator.qml42
-rw-r--r--src/quickcontrols/macos/images/checkmark.pngbin0 -> 210 bytes
-rw-r--r--src/quickcontrols/macos/images/checkmark@2x.pngbin0 -> 289 bytes
-rw-r--r--src/quickcontrols/macos/images/checkmark@3x.pngbin0 -> 359 bytes
-rw-r--r--src/quickcontrols/macos/images/menuarrow.pngbin0 -> 183 bytes
-rw-r--r--src/quickcontrols/macos/images/menuarrow@2x.pngbin0 -> 266 bytes
-rw-r--r--src/quickcontrols/macos/images/menuarrow@3x.pngbin0 -> 260 bytes
-rw-r--r--src/quickcontrols/macos/impl/CMakeLists.txt1
-rw-r--r--src/quickcontrols/macos/impl/CheckIndicator.qml21
-rw-r--r--src/quickcontrols/qquickstyle.cpp2
-rw-r--r--src/quickcontrols/qt_cmdline.cmake1
-rw-r--r--src/quickcontrols/windows/CMakeLists.txt13
-rw-r--r--src/quickcontrols/windows/Menu.qml74
-rw-r--r--src/quickcontrols/windows/MenuBar.qml35
-rw-r--r--src/quickcontrols/windows/MenuBarItem.qml47
-rw-r--r--src/quickcontrols/windows/MenuItem.qml74
-rw-r--r--src/quickcontrols/windows/MenuSeparator.qml23
-rw-r--r--src/quickcontrols/windows/ScrollIndicator.qml42
-rw-r--r--src/quickcontrols/windows/images/checkmark.pngbin0 -> 200 bytes
-rw-r--r--src/quickcontrols/windows/images/checkmark@2x.pngbin0 -> 252 bytes
-rw-r--r--src/quickcontrols/windows/images/checkmark@3x.pngbin0 -> 321 bytes
-rw-r--r--src/quickcontrols/windows/images/menuarrow.pngbin0 -> 165 bytes
-rw-r--r--src/quickcontrols/windows/images/menuarrow@2x.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols/windows/images/menuarrow@3x.pngbin0 -> 205 bytes
-rw-r--r--src/quickcontrols/windows/impl/CMakeLists.txt1
-rw-r--r--src/quickcontrols/windows/impl/CheckIndicator.qml21
-rw-r--r--src/quickcontrolsimpl/qquickcolorimage.cpp4
-rw-r--r--src/quickcontrolsimpl/qquickiconimage.cpp6
-rw-r--r--src/quickcontrolsimpl/qquickninepatchimage.cpp6
-rw-r--r--src/quicklayouts/qquicklayout.cpp58
-rw-r--r--src/quicklayouts/qquicklayout_p.h28
-rw-r--r--src/quicklayouts/qquicklinearlayout.cpp2
-rw-r--r--src/quicknativestyle/qstyle/qquickcommonstyle.cpp6
-rw-r--r--src/quickshapes/CMakeLists.txt2
-rw-r--r--src/quickshapes/qquickshape.cpp128
-rw-r--r--src/quickshapes/qquickshape_p.h11
-rw-r--r--src/quickshapes/qquickshape_p_p.h14
-rw-r--r--src/quickshapes/qquickshapecurverenderer.cpp70
-rw-r--r--src/quickshapes/qquickshapecurverenderer_p.h16
-rw-r--r--src/quickshapes/qquickshapegenericrenderer.cpp305
-rw-r--r--src/quickshapes/qquickshapegenericrenderer_p.h76
-rw-r--r--src/quickshapes/qquickshapesoftwarerenderer.cpp21
-rw-r--r--src/quickshapes/qquickshapesoftwarerenderer_p.h3
-rw-r--r--src/quickshapes/shaders_ng/conicalgradient.frag1
-rw-r--r--src/quickshapes/shaders_ng/conicalgradient.vert4
-rw-r--r--src/quickshapes/shaders_ng/lineargradient.frag1
-rw-r--r--src/quickshapes/shaders_ng/lineargradient.vert4
-rw-r--r--src/quickshapes/shaders_ng/radialgradient.frag1
-rw-r--r--src/quickshapes/shaders_ng/radialgradient.vert4
-rw-r--r--src/quickshapes/shaders_ng/texturefill.frag25
-rw-r--r--src/quickshapes/shaders_ng/texturefill.vert31
-rw-r--r--src/quicktemplates/CMakeLists.txt8
-rw-r--r--src/quicktemplates/qquickabstractbutton.cpp93
-rw-r--r--src/quicktemplates/qquickabstractbutton_p.h2
-rw-r--r--src/quicktemplates/qquickabstractbutton_p_p.h1
-rw-r--r--src/quicktemplates/qquickaction.cpp7
-rw-r--r--src/quicktemplates/qquickdialog.cpp28
-rw-r--r--src/quicktemplates/qquickdialog_p.h2
-rw-r--r--src/quicktemplates/qquickdialog_p_p.h2
-rw-r--r--src/quicktemplates/qquickdrawer.cpp5
-rw-r--r--src/quicktemplates/qquickdrawer_p_p.h2
-rw-r--r--src/quicktemplates/qquickheaderview.cpp82
-rw-r--r--src/quicktemplates/qquickheaderview_p.h14
-rw-r--r--src/quicktemplates/qquickheaderview_p_p.h9
-rw-r--r--src/quicktemplates/qquickmenu.cpp650
-rw-r--r--src/quicktemplates/qquickmenu_p.h3
-rw-r--r--src/quicktemplates/qquickmenu_p_p.h39
-rw-r--r--src/quicktemplates/qquickmenubar.cpp563
-rw-r--r--src/quicktemplates/qquickmenubar_p.h3
-rw-r--r--src/quicktemplates/qquickmenubar_p_p.h35
-rw-r--r--src/quicktemplates/qquickmenubaritem.cpp1
-rw-r--r--src/quicktemplates/qquickmenuitem.cpp79
-rw-r--r--src/quicktemplates/qquickmenuitem_p.h12
-rw-r--r--src/quicktemplates/qquickmenuitem_p_p.h1
-rw-r--r--src/quicktemplates/qquicknativeicon.cpp50
-rw-r--r--src/quicktemplates/qquicknativeicon_p.h57
-rw-r--r--src/quicktemplates/qquicknativeiconloader.cpp66
-rw-r--r--src/quicktemplates/qquicknativeiconloader_p.h54
-rw-r--r--src/quicktemplates/qquicknativemenuitem.cpp329
-rw-r--r--src/quicktemplates/qquicknativemenuitem_p.h81
-rw-r--r--src/quicktemplates/qquickpage.cpp5
-rw-r--r--src/quicktemplates/qquickpage_p.h3
-rw-r--r--src/quicktemplates/qquickpopup.cpp251
-rw-r--r--src/quicktemplates/qquickpopup_p.h21
-rw-r--r--src/quicktemplates/qquickpopup_p_p.h10
-rw-r--r--src/quicktemplates/qquickpopupitem.cpp12
-rw-r--r--src/quicktemplates/qquickpopupitem_p_p.h2
-rw-r--r--src/quicktemplates/qquickpopuppositioner.cpp53
-rw-r--r--src/quicktemplates/qquickpopupwindow.cpp277
-rw-r--r--src/quicktemplates/qquickpopupwindow_p_p.h57
-rw-r--r--src/quicktemplates/qquickselectionrectangle.cpp4
-rw-r--r--src/quicktemplates/qquickspinbox.cpp15
-rw-r--r--src/quicktemplates/qquicksplitview.cpp39
-rw-r--r--src/quicktemplates/qquicktooltip.cpp7
-rw-r--r--src/quicktestutils/quick/visualtestutils_p.h6
-rw-r--r--src/quickvectorimage/generator/qquickitemgenerator.cpp2
-rw-r--r--src/quickvectorimage/generator/qquicknodeinfo_p.h1
-rw-r--r--src/quickvectorimage/generator/qquickqmlgenerator.cpp54
-rw-r--r--src/quickvectorimage/generator/qquickqmlgenerator_p.h33
-rw-r--r--src/quickvectorimage/generator/qsvgvisitorimpl.cpp13
-rw-r--r--src/quickvectorimage/qquickvectorimage.cpp92
-rw-r--r--src/quickvectorimage/qquickvectorimage_p.h16
-rw-r--r--src/quickvectorimage/qquickvectorimage_p_p.h1
-rw-r--r--src/quickwidgets/qquickwidget.cpp68
-rw-r--r--src/quickwidgets/qquickwidget_p.h2
1017 files changed, 26053 insertions, 3444 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ca83200cf5..56992dda9b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -95,6 +95,7 @@ add_subdirectory(qmldom)
# Build qmlcachegen now, so that we can use it in src/imports.
if(QT_FEATURE_xmlstreamwriter)
+ add_subdirectory(../tools/qmlaotstats qmlaotstats)
add_subdirectory(../tools/qmlcachegen qmlcachegen)
endif()
diff --git a/src/plugins/qmllint/quick/quicklintplugin.cpp b/src/plugins/qmllint/quick/quicklintplugin.cpp
index 15b947a10c..52d4d759e3 100644
--- a/src/plugins/qmllint/quick/quicklintplugin.cpp
+++ b/src/plugins/qmllint/quick/quicklintplugin.cpp
@@ -675,7 +675,7 @@ void QmlLintQuickPlugin::registerPasses(QQmlSA::PassManager *manager,
{ { "columnWidthProvider", { "", "function" } },
{ "rowHeightProvider", { "", "function" } } });
addAttachedWarning({ "QtQuick", "Accessible" }, { { "QtQuick", "Item" } },
- "Accessible must be attached to an Item");
+ "Accessible must be attached to an Item or an Action");
addAttachedWarning({ "QtQuick", "LayoutMirroring" },
{ { "QtQuick", "Item" }, { "QtQuick", "Window" } },
"LayoutDirection attached property only works with Items and Windows");
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
index 3bd37878a8..f678eb905b 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
@@ -761,7 +761,8 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth
QV4::Scope scope(v4);
int lineNumber = 0;
- QV4::ScopedFunctionObject oldMethod(scope, vmeMetaObject->vmeMethod(prop->coreIndex()));
+ QV4::Scoped<QV4::JavaScriptFunctionObject> oldMethod(
+ scope, vmeMetaObject->vmeMethod(prop->coreIndex()));
if (oldMethod && oldMethod->d()->function)
lineNumber = oldMethod->d()->function->compiledFunction->location.line();
diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt
index cbcdc2f8f9..b52a734bd5 100644
--- a/src/qml/CMakeLists.txt
+++ b/src/qml/CMakeLists.txt
@@ -31,65 +31,13 @@ if(ANDROID)
"${INSTALL_CMAKE_NAMESPACE}AndroidQmlMacros.cmake")
endif()
-set_source_files_properties(
- qml/qqmlcomponent.h qml/qqmlcomponent.cpp qml/qqmlcomponent_p.h
- qml/qqmlcomponentattached_p.h
- qml/qqmlscriptstring.h qml/qqmlscriptstring_p.h qml/qqmlscriptstring.cpp
- PROPERTIES
- SKIP_AUTOMOC TRUE
-)
-
-set(extra_manual_moc_deps "")
-if(QT_FEATURE_qml_network)
- list(APPEND extra_manual_moc_deps Qt6::Network)
-endif()
-# We want QQmlComponent, QQmlComponentAttached, and QQmlScriptString to be available as metatypes in
-# the builtins, but without depending on QtQml and without duplicating the metaobjects.
-qt_manual_moc(extra_builtins_moc_files
- OUTPUT_MOC_JSON_FILES extra_builtins_json_list
- qml/qqmlcomponent.h
- qml/qqmlcomponentattached_p.h
- qml/qqmlscriptstring.h
- TARGETS Qt6::Qml Qt6::Core ${extra_manual_moc_deps}
-)
-
-# The moc files are included directly by qqmlcomponent.cpp and qqmlscriptstring.cpp
-set_source_files_properties(${extra_builtins_moc_files} PROPERTIES HEADER_FILE_ONLY ON)
-
-qt_internal_add_module(QmlBuiltins
- STATIC
- NO_GENERATE_METATYPES # we do that manually below
- SOURCES
- qqmlbuiltins_p.h
-)
-
-add_custom_target(ExtraBuiltinsJson DEPENDS ${extra_builtins_json_list})
-add_custom_target(ExtraBuiltinsMocs DEPENDS ${extra_builtins_moc_files})
-
-target_link_libraries(QmlBuiltins PRIVATE Qt::Core Qt::QmlIntegration)
-
-# We generally need to copy the files into the build directory,
-# so that they are located together with the QML modules
-qt_path_join(qml_build_dir "${QT_BUILD_DIR}" "${INSTALL_QMLDIR}")
-
-# Simulate conditions that qt6_add_qml_module() would normally set up for us
-set_target_properties(QmlBuiltins PROPERTIES
- QT_QML_MODULE_VERSION 1.0
- QT_QML_MODULE_URI QML
- QT_QML_MODULE_TYPEINFO builtins.qmltypes
- QT_QML_MODULE_OUTPUT_DIRECTORY ${qml_build_dir}
-)
-
qt_internal_add_qml_module(Qml
- URI "QtQml.Base"
- VERSION "${PROJECT_VERSION}"
+ URI "QML"
+ VERSION "1.0"
DESIGNER_SUPPORTED
__QT_INTERNAL_SYSTEM_MODULE
- PLUGIN_TARGET qmlplugin
- CLASS_NAME QtQmlPlugin
PLUGIN_TYPES qmltooling
- IMPORTS
- QML/1.0
+ NO_PLUGIN
SOURCES
../3rdparty/masm/assembler/ARM64Assembler.h
../3rdparty/masm/assembler/ARMv7Assembler.cpp ../3rdparty/masm/assembler/ARMv7Assembler.h
@@ -173,13 +121,13 @@ qt_internal_add_qml_module(Qml
common/qqmljsfixedpoolarray_p.h
common/qqmljsmemorypool_p.h
common/qqmljssourcelocation_p.h
+ common/qqmlsignalnames_p.h common/qqmlsignalnames.cpp
+ common/qqmltranslation.cpp common/qqmltranslation_p.h
common/qv4alloca_p.h
common/qv4calldata_p.h
common/qv4compileddata.cpp common/qv4compileddata_p.h
common/qv4staticvalue_p.h
common/qv4stringtoarrayindex_p.h
- common/qqmltranslation.cpp common/qqmltranslation_p.h
- common/qqmlsignalnames_p.h common/qqmlsignalnames.cpp
compat/removed_api.cpp
compiler/qqmlirbuilder.cpp compiler/qqmlirbuilder_p.h
compiler/qv4bytecodegenerator.cpp compiler/qv4bytecodegenerator_p.h
@@ -258,6 +206,7 @@ qt_internal_add_qml_module(Qml
jsruntime/qv4qmetaobjectwrapper.cpp jsruntime/qv4qmetaobjectwrapper_p.h
jsruntime/qv4qmlcontext.cpp jsruntime/qv4qmlcontext_p.h
jsruntime/qv4qobjectwrapper.cpp jsruntime/qv4qobjectwrapper_p.h
+ jsruntime/qv4referenceobject.cpp jsruntime/qv4referenceobject_p.h
jsruntime/qv4reflect.cpp jsruntime/qv4reflect_p.h
jsruntime/qv4regexp.cpp jsruntime/qv4regexp_p.h
jsruntime/qv4regexpobject.cpp jsruntime/qv4regexpobject_p.h
@@ -267,6 +216,7 @@ qt_internal_add_qml_module(Qml
jsruntime/qv4runtimecodegen.cpp jsruntime/qv4runtimecodegen_p.h
jsruntime/qv4scopedvalue_p.h
jsruntime/qv4script.cpp jsruntime/qv4script_p.h
+ jsruntime/qv4sequenceobject.cpp jsruntime/qv4sequenceobject_p.h
jsruntime/qv4setiterator.cpp jsruntime/qv4setiterator_p.h
jsruntime/qv4setobject.cpp jsruntime/qv4setobject_p.h
jsruntime/qv4sparsearray.cpp jsruntime/qv4sparsearray_p.h
@@ -281,9 +231,7 @@ qt_internal_add_qml_module(Qml
jsruntime/qv4value.cpp jsruntime/qv4value_p.h
jsruntime/qv4variantobject.cpp jsruntime/qv4variantobject_p.h
jsruntime/qv4vme_moth.cpp jsruntime/qv4vme_moth_p.h
- jsruntime/qv4sequenceobject.cpp jsruntime/qv4sequenceobject_p.h
jsruntime/qv4vtable_p.h
- jsruntime/qv4referenceobject.cpp jsruntime/qv4referenceobject_p.h
memory/qv4heap_p.h
memory/qv4mm.cpp memory/qv4mm_p.h
memory/qv4mmdefs_p.h
@@ -296,10 +244,10 @@ qt_internal_add_qml_module(Qml
parser/qqmljsglobal_p.h
parser/qqmljskeywords_p.h
parser/qqmljslexer.cpp parser/qqmljslexer_p.h
+ qml/ftw/qbipointer_p.h
qml/ftw/qdoubleendedlist_p.h
qml/ftw/qfieldlist_p.h
qml/ftw/qfinitestack_p.h
- qml/ftw/qbipointer_p.h
qml/ftw/qhashedstring.cpp qml/ftw/qhashedstring_p.h
qml/ftw/qintrusivelist.cpp qml/ftw/qintrusivelist_p.h
qml/ftw/qlazilyallocated_p.h
@@ -312,10 +260,10 @@ qt_internal_add_qml_module(Qml
qml/ftw/qrecursionwatcher_p.h
qml/ftw/qrecyclepool_p.h
qml/ftw/qstringhash_p.h
- qml/qqmlregistration.h
qml/qqml.cpp qml/qqml.h
qml/qqmlabstractbinding.cpp qml/qqmlabstractbinding_p.h
qml/qqmlabstracturlinterceptor.cpp qml/qqmlabstracturlinterceptor.h
+ qml/qqmlanybinding_p.h
qml/qqmlapplicationengine.cpp qml/qqmlapplicationengine.h qml/qqmlapplicationengine_p.h
qml/qqmlbinding.cpp qml/qqmlbinding_p.h
qml/qqmlboundsignal.cpp qml/qqmlboundsignal_p.h
@@ -339,6 +287,7 @@ qt_internal_add_qml_module(Qml
qml/qqmlextensionplugin.cpp qml/qqmlextensionplugin.h qml/qqmlextensionplugin_p.h
qml/qqmlfile.cpp qml/qqmlfile.h
qml/qqmlfileselector.cpp qml/qqmlfileselector.h qml/qqmlfileselector_p.h
+ qml/qqmlfinalizer.cpp qml/qqmlfinalizer_p.h
qml/qqmlglobal.cpp qml/qqmlglobal_p.h
qml/qqmlguard_p.h
qml/qqmlguardedcontextdata_p.h
@@ -349,8 +298,7 @@ qt_internal_add_qml_module(Qml
qml/qqmljavascriptexpression.cpp qml/qqmljavascriptexpression_p.h
qml/qqmllist.cpp qml/qqmllist.h qml/qqmllist_p.h
qml/qqmllistwrapper.cpp qml/qqmllistwrapper_p.h
- qml/qqmlloggingcategory.cpp qml/qqmlloggingcategory_p.h
- qml/qqmlmetamoduleregistration.cpp
+ qml/qqmlloggingcategorybase_p.h
qml/qqmlmetaobject.cpp qml/qqmlmetaobject_p.h
qml/qqmlmetatype.cpp qml/qqmlmetatype_p.h
qml/qqmlmetatypedata.cpp qml/qqmlmetatypedata_p.h
@@ -366,7 +314,6 @@ qt_internal_add_qml_module(Qml
qml/qqmlprivate.h
qml/qqmlproperty.cpp qml/qqmlproperty.h qml/qqmlproperty_p.h
qml/qqmlpropertybinding.cpp qml/qqmlpropertybinding_p.h
- qml/qqmlanybinding_p.h
qml/qqmlpropertycache.cpp qml/qqmlpropertycache_p.h
qml/qqmlpropertycachecreator.cpp qml/qqmlpropertycachecreator_p.h
qml/qqmlpropertycachemethodarguments_p.h
@@ -377,9 +324,9 @@ qt_internal_add_qml_module(Qml
qml/qqmlpropertytopropertybinding.cpp qml/qqmlpropertytopropertybinding_p.h
qml/qqmlpropertyvalidator.cpp qml/qqmlpropertyvalidator_p.h
qml/qqmlpropertyvalueinterceptor.cpp qml/qqmlpropertyvalueinterceptor_p.h
- qml/qqmlfinalizer.cpp qml/qqmlfinalizer_p.h
qml/qqmlpropertyvaluesource.cpp qml/qqmlpropertyvaluesource.h
qml/qqmlproxymetaobject.cpp qml/qqmlproxymetaobject_p.h
+ qml/qqmlregistration.h
qml/qqmlscriptblob.cpp qml/qqmlscriptblob_p.h
qml/qqmlscriptdata.cpp qml/qqmlscriptdata_p.h
qml/qqmlscriptstring.cpp qml/qqmlscriptstring.h qml/qqmlscriptstring_p.h
@@ -403,10 +350,9 @@ qt_internal_add_qml_module(Qml
qml/qqmlvmemetaobject.cpp qml/qqmlvmemetaobject_p.h
qmldirparser/qqmldirparser.cpp qmldirparser/qqmldirparser_p.h
qmldirparser/qqmlimportresolver.cpp qmldirparser/qqmlimportresolver_p.h
+ qqmlbuiltins_p.h
qtqmlcompilerglobal.h qtqmlcompilerglobal_p.h
qtqmlglobal.h qtqmlglobal_p.h
- types/qqmlbind.cpp types/qqmlbind_p.h
- types/qqmlconnections.cpp types/qqmlconnections_p.h
util/qqmlpropertymap.cpp util/qqmlpropertymap.h
qmltc/qqmltcobjectcreationhelper_p.h
@@ -440,7 +386,6 @@ qt_internal_add_qml_module(Qml
jsruntime/qv4module.cpp # QV4::Compiler::Module vs. QV4::Module
jsruntime/qv4vme_moth.cpp # 'MOTH_BEGIN_INSTR' macro redefined (from qv4instr_moth.cpp)
qml/qqmltypecompiler.cpp # 'COMPILE_EXCEPTION' macro redefined (from qqmlirbuilder.cpp)
- qml/qqmlmetamoduleregistration.cpp # declares 'registration' clashing with qml_* files
DEFINES
BUILDING_QT__
ENABLE_ASSEMBLER_WX_EXCLUSIVE=1
@@ -486,12 +431,11 @@ qt_internal_add_qml_module(Qml
PUBLIC_LIBRARIES
Qt::Core
Qt::QmlIntegration
- Qt::QmlBuiltins
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
- Qt::QmlBuiltinsPrivate
EXTRA_CMAKE_FILES
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}qmldirTemplate.cmake.in"
+ "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}qt.conf.in"
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlPluginTemplate.cpp.in"
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlFindQmlscInternal.cmake"
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlDeploySupport.cmake"
@@ -505,62 +449,44 @@ qt_internal_add_qml_module(Qml
POLICIES
QTP0001
QTP0004
+ QTP0005
)
_qt_internal_add_qml_deploy_info_finalizer(Qml)
-target_include_directories(QmlBuiltins PRIVATE
- $<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::QmlPrivate,INTERFACE_INCLUDE_DIRECTORIES>
-)
-
-set(builtins_typeregistration_args
- MANUAL_MOC_JSON_FILES ${extra_builtins_json_list}
- REGISTRATIONS_TARGET Qml
-)
-
-get_target_property(qt_namespace ${QT_CMAKE_EXPORT_NAMESPACE}::Core _qt_namespace)
-if(qt_namespace)
- list(APPEND builtins_typeregistration_args NAMESPACE ${qt_namespace})
-endif()
-
-_qt_internal_qml_type_registration(QmlBuiltins ${builtins_typeregistration_args})
-add_dependencies(QmlBuiltins ExtraBuiltinsJson)
+qt_path_join(qml_root_dir "${QT_BUILD_DIR}" "${INSTALL_QMLDIR}")
+get_target_property(qml_build_dir Qml QT_QML_MODULE_OUTPUT_DIRECTORY)
_qt_internal_get_tool_wrapper_script_path(tool_wrapper)
add_custom_command(
OUTPUT
- "${qml_build_dir}/jsroot.qmltypes"
+ "${qml_root_dir}/jsroot.qmltypes"
DEPENDS
${QT_CMAKE_EXPORT_NAMESPACE}::qmltyperegistrar
COMMAND
${tool_wrapper}
$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qmltyperegistrar>
- --jsroot --generate-qmltypes "${qml_build_dir}/jsroot.qmltypes"
+ --jsroot --generate-qmltypes "${qml_root_dir}/jsroot.qmltypes"
COMMENT "Generating jsroot.qmltypes"
VERBATIM
)
-get_target_property(builtins_metatypes_file "QmlBuiltins" INTERFACE_QT_META_TYPES_BUILD_FILE)
-
-_qt_internal_get_metatypes_install_dir(
- ""
- "${INSTALL_ARCHDATADIR}"
- metatypes_install_dir
-)
-
-_qt_internal_assign_install_metatypes_files_and_properties(
- QmlBuiltins
- INSTALL_DIR "${metatypes_install_dir}"
-)
-
-qt_install(
- FILES "${builtins_metatypes_file}"
- DESTINATION "${metatypes_install_dir}"
+add_custom_command(
+ OUTPUT
+ "${qml_root_dir}/builtins.qmltypes"
+ DEPENDS
+ "${qml_build_dir}/plugins.qmltypes"
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different
+ "${qml_build_dir}/plugins.qmltypes"
+ "${qml_root_dir}/builtins.qmltypes"
+ COMMENT "Copying builtins.qmltypes"
+ VERBATIM
)
set(builtins_output_files "")
-list(APPEND builtins_output_files "${qml_build_dir}/builtins.qmltypes")
-list(APPEND builtins_output_files "${qml_build_dir}/jsroot.qmltypes")
+list(APPEND builtins_output_files "${qml_root_dir}/builtins.qmltypes")
+list(APPEND builtins_output_files "${qml_root_dir}/jsroot.qmltypes")
add_custom_target(BuiltinsOutput DEPENDS ${builtins_output_files})
@@ -569,9 +495,6 @@ qt_install(
DESTINATION "${INSTALL_QMLDIR}"
)
-add_dependencies(Qml ExtraBuiltinsMocs)
-add_dependencies(Qml BuiltinsOutput)
-
qt_update_ignore_pch_source(Qml "compat/removed_api.cpp")
set_source_files_properties(compat/removed_api.cpp
@@ -583,30 +506,24 @@ qt_internal_add_qml_module(QmlMeta
URI "QtQml"
VERSION "${PROJECT_VERSION}"
DESIGNER_SUPPORTED
- CLASS_NAME QtQmlMetaPlugin
- PLUGIN_TARGET QmlMeta
-
- # Prevent type registration
- NO_GENERATE_QMLTYPES
-
+ __QT_INTERNAL_SYSTEM_MODULE
+ PLUGIN_TARGET qmlplugin
+ CLASS_NAME QtQmlPlugin
PAST_MAJOR_VERSIONS 2
IMPORTS
- QtQml.Base/auto
+ QML/1.0
${module_dynamic_qml_imports}
+ SOURCES
+ types/qqmlbind.cpp types/qqmlbind_p.h
+ types/qqmlconnections.cpp types/qqmlconnections_p.h
+ types/qqmlloggingcategory.cpp types/qqmlloggingcategory_p.h
+ LIBRARIES
+ Qml
+ QmlModels
+ GENERATE_CPP_EXPORTS
)
-# Add the QtQml qmldir to libQtQml, too.
-# Since we also provide the (bare bones) type registration in libQtQml,
-# this makes the complete module reside in libQtQml. There is no need to
-# load the QmlMeta plugin, then.
-# Se still provide the plugin so that static linking works.
-get_target_property(qtqml_out_dir QmlMeta QT_QML_MODULE_OUTPUT_DIRECTORY)
-qt_internal_add_resource(Qml "qmlMetaQmldir"
- PREFIX
- "/qt-project.org/imports/QtQml"
- FILES
- ${qtqml_out_dir}/qmldir
-)
+add_dependencies(QmlMeta BuiltinsOutput)
# Linking to the static qml plugin should also automatically link to the worker script
# static plugin otherwise you get errors like
@@ -614,14 +531,15 @@ qt_internal_add_resource(Qml "qmlMetaQmldir"
# import QtQuick 2.0
# ^
if(QT_FEATURE_qml_worker_script)
+ target_link_libraries(QmlMeta PRIVATE QmlWorkerScript)
_qt_internal_add_qml_static_plugin_dependency(qmlplugin workerscriptplugin)
endif()
-# Same for the QmlMeta qml plugin, otherwise you get
+# Same for the QmlModels qml plugin, otherwise you get
# module "QtQuick" version 6.6 cannot be imported because:
-# module "QtQml" plugin "qmlmetaplugin" not found
+# module "QtQml.Models" plugin "modelsplugin" not found
# import QtQuick
# ^
-_qt_internal_add_qml_static_plugin_dependency(qmlplugin QmlMeta)
+_qt_internal_add_qml_static_plugin_dependency(qmlplugin modelsplugin)
# special case begin remove the block, handled manually
# QLALR Grammars:
@@ -714,6 +632,12 @@ qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_animation
animations/qparallelanimationgroupjob.cpp animations/qparallelanimationgroupjob_p.h
animations/qpauseanimationjob.cpp animations/qpauseanimationjob_p.h
animations/qsequentialanimationgroupjob.cpp animations/qsequentialanimationgroupjob_p.h
+ INCLUDE_DIRECTORIES
+ animations
+)
+
+qt_internal_extend_target(QmlMeta CONDITION QT_FEATURE_qml_animation
+ SOURCES
types/qqmltimer.cpp types/qqmltimer_p.h
INCLUDE_DIRECTORIES
animations
@@ -778,6 +702,11 @@ qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_locale
qml/qqmllocale.cpp qml/qqmllocale_p.h
)
+qt_internal_extend_target(QmlMeta CONDITION QT_FEATURE_qml_locale
+ SOURCES
+ types/qqmllocaleenums_p.h
+)
+
qt_internal_extend_target(Qml CONDITION ANDROID
DEFINES
LIBS_SUFFIX="_${ANDROID_ABI}.so" # special case
@@ -875,10 +804,8 @@ endif()
# "unknown IID" issue when moc processes plugin sources, because of missing header aliases.
# Qml_sync_headers target is created later by the finalizer in the directory scope so we add this
# dependency manually instead of relying on qt_internal_add_qml_module logic. Same is applicable
-# for the QmlMeta and the QmlBuiltins target.
+# for the QmlMeta target.
set_property(TARGET qmlplugin APPEND PROPERTY AUTOGEN_TARGET_DEPENDS
Qml_sync_headers)
set_property(TARGET QmlMeta APPEND PROPERTY AUTOGEN_TARGET_DEPENDS
Qml_sync_headers)
-set_property(TARGET QmlBuiltins APPEND PROPERTY AUTOGEN_TARGET_DEPENDS
- Qml_sync_headers)
diff --git a/src/qml/Qt6AndroidQmlMacros.cmake b/src/qml/Qt6AndroidQmlMacros.cmake
index 5f6f01fd76..0a17665d5b 100644
--- a/src/qml/Qt6AndroidQmlMacros.cmake
+++ b/src/qml/Qt6AndroidQmlMacros.cmake
@@ -135,5 +135,13 @@ function(_qt_internal_generate_android_qml_deployment_settings out_var target)
_qt_internal_add_tool_to_android_deployment_settings(${out_var} qmlimportscanner
"qml-importscanner-binary" ${target})
+ # Add qml-dom-binary binary path
+ _qt_internal_add_tool_to_android_deployment_settings(${out_var} qmldom "qml-dom-binary"
+ "${target}")
+
+
+ _qt_internal_add_android_deployment_list_property(${out_var} "qml-files-for-code-generator"
+ ${target} "_qt_qml_files_for_java_generator")
+
set(${out_var} "${${out_var}}" PARENT_SCOPE)
endfunction()
diff --git a/src/qml/Qt6QmlBuildInternals.cmake b/src/qml/Qt6QmlBuildInternals.cmake
index 418b552692..7b181fabde 100644
--- a/src/qml/Qt6QmlBuildInternals.cmake
+++ b/src/qml/Qt6QmlBuildInternals.cmake
@@ -94,7 +94,6 @@ function(qt_internal_add_qml_module target)
)
# TODO: Remove these once all repos have been updated to not use them
set(ignore_option_args
- SKIP_TYPE_REGISTRATION # Now always done
PLUGIN_OPTIONAL # Now the default
GENERATE_QMLTYPES # Now the default
INSTALL_QMLTYPES # Now the default
diff --git a/src/qml/Qt6QmlDeploySupport.cmake b/src/qml/Qt6QmlDeploySupport.cmake
index a230e71409..1b43059cc2 100644
--- a/src/qml/Qt6QmlDeploySupport.cmake
+++ b/src/qml/Qt6QmlDeploySupport.cmake
@@ -159,6 +159,11 @@ function(_qt_internal_deploy_qml_imports_for_target)
# file names, so account for those. There should never be plugin
# libraries for more than one QML module in the directory, so we
# shouldn't need to worry about matching plugins we don't want.
+ #
+ # install_qmldir and install_plugin do not contain $ENV{DESTDIR},
+ # whereas dest_qmldir and dest_plugin do.
+ # The install_ variants are used in file(INSTALL) to avoid double DESTDIR in paths.
+ # Other code should reference the dest_ variants instead.
set(relative_qmldir "${arg_QML_DIR}/${entry_RELATIVEPATH}")
if("${CMAKE_INSTALL_PREFIX}" STREQUAL "")
set(install_qmldir "./${relative_qmldir}")
@@ -180,6 +185,12 @@ function(_qt_internal_deploy_qml_imports_for_target)
file(INSTALL "${entry_PATH}/qmldir" DESTINATION "${install_qmldir}")
+ if(DEFINED __QT_DEPLOY_TARGET_${entry_LINKTARGET}_FILE AND
+ __QT_DEPLOY_TARGET_${entry_LINKTARGET}_TYPE STREQUAL "STATIC_LIBRARY")
+ # If the QML plugin is built statically, skip further deployment.
+ continue()
+ endif()
+
if(__QT_DEPLOY_POST_BUILD)
# We are being invoked as a post-build step. The plugin might
# not exist yet, so we can't even glob for it, let alone copy
diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake
index 5352f896f6..e37e99ea6a 100644
--- a/src/qml/Qt6QmlMacros.cmake
+++ b/src/qml/Qt6QmlMacros.cmake
@@ -13,6 +13,129 @@ set(__qt_qml_macros_module_base_dir "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "
include(GNUInstallDirs)
_qt_internal_add_deploy_support("${CMAKE_CURRENT_LIST_DIR}/Qt6QmlDeploySupport.cmake")
+# This function is used to parse DEPENDENCY and IMPORT entries passed to qt_add_qml_module
+# It takes the entry as a mandatory argument, and then sets the following
+# user provided properties in the callers scope
+# OUTPUT_URI <property>: the URI of the module; mandatory argument
+# OUTPUT_VERSION <property>: the requested version of the module; will potentially be empty; mandatory
+# OUTPUT_MODULE_LOCATION <property>: the folder in which the module is located; optional; can be used to extract potential import path
+# OUTPUT_MODULE_TARGET <property>: the target corresponding to the module
+
+function(_qt_internal_parse_qml_module_dependency dependency was_marked_as_target)
+ set(args_option "")
+ set(args_single OUTPUT_URI OUTPUT_VERSION OUTPUT_MODULE_LOCATION OUTPUT_MODULE_TARGET)
+ set(args_multi QML_FILES IMPORT_PATHS)
+
+ cmake_parse_arguments(PARSE_ARGV 2 arg
+ "${args_option}" "${args_single}" "${args_multi}"
+ )
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown/unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+
+ if(NOT arg_OUTPUT_URI)
+ message(FATAL_ERROR "Missing output URI variable")
+ endif()
+ if(NOT arg_OUTPUT_VERSION)
+ message(FATAL_ERROR "Missing output version variable")
+ endif()
+
+ set(dep_version "")
+ set(dep_target_or_uri "")
+ string(FIND "${dependency}" "/" slash_position REVERSE)
+ if(slash_position EQUAL -1)
+ set(dep_target_or_uri "${dependency}")
+ else()
+ string(SUBSTRING "${dependency}" 0 ${slash_position} dep_module)
+ math(EXPR slash_position "${slash_position} + 1")
+ string(SUBSTRING "${dependency}" ${slash_position} -1 dep_version)
+ if(NOT dep_version MATCHES "^([0-9]+(\\.[0-9]+)?|auto)$")
+ message(FATAL_ERROR
+ "Invalid module dependency version number. "
+ "Expected 'VersionMajor', 'VersionMajor.VersionMinor' or 'auto'."
+ )
+ endif()
+ set(dep_target_or_uri "${dep_module}")
+ endif()
+ if("${was_marked_as_target}" AND NOT TARGET ${dep_target_or_uri})
+ message(FATAL_ERROR "Argument ${dep_target_or_uri} is not a target!")
+ endif()
+ if("${was_marked_as_target}")
+ qt6_query_qml_module(${dep_target_or_uri}
+ URI dependency_uri
+ QMLDIR qmldir_location
+ )
+ set(dep_module ${dependency_uri})
+ else()
+ set(dep_module "${dep_target_or_uri}")
+ endif()
+ set(${arg_OUTPUT_URI} ${dep_module} PARENT_SCOPE)
+ set(${arg_OUTPUT_VERSION} ${dep_version} PARENT_SCOPE)
+ if(arg_OUTPUT_MODULE_LOCATION)
+ if(was_marked_as_target)
+ if(NOT qmldir_location)
+ message(FATAL_ERROR "module has no qmldir! Given target was ${dep_target_or_uri}")
+ endif()
+ set(module_location "${qmldir_location}")
+ string(REGEX MATCHALL "\\." matches "${dependency_uri}")
+ list(LENGTH matches go_up_count)
+ # inclusive, which is what we want here: go up once for the qmldir,
+ # and then once per separated component
+ foreach(i RANGE ${go_up_count})
+ get_filename_component(module_location "${module_location}" DIRECTORY)
+ endforeach()
+ set(${arg_OUTPUT_MODULE_LOCATION} "${module_location}" PARENT_SCOPE)
+ else()
+ set(${arg_OUTPUT_MODULE_LOCATION} "NOTFOUND" PARENT_SCOPE)
+ endif()
+ endif()
+ if (arg_OUTPUT_MODULE_TARGET AND was_marked_as_target)
+ set(${arg_OUTPUT_MODULE_TARGET} "${dep_target_or_uri}" PARENT_SCOPE)
+ else()
+ set(${arg_OUTPUT_MODULE_TARGET} "" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_qt_internal_write_deferred_builddir_qtconf folder)
+ set(qt_all_qml_output_dirs "")
+ get_directory_property(targets
+ DIRECTORY "${folder}"
+ QT_QML_TARGETS_FOR_DEFERRED_QTCONF_WRITEOUT
+ )
+ set(qtconf_file "${folder}/qt.conf")
+ foreach(target IN LISTS ${targets})
+ get_target_property(dependency_targets "${target}" QT_QML_DEPENDENT_QML_MODULE_TARGETS)
+ if(NOT dependency_targets)
+ continue()
+ endif()
+ foreach(dep_target ${dependency_targets})
+ qt6_query_qml_module(${dep_target}
+ QMLDIR qmldir_location
+ )
+ get_filename_component(module_location "${qmldir_location}" DIRECTORY)
+ get_filename_component(module_import_path "${module_location}" DIRECTORY)
+ list(APPEND qt_all_qml_output_dirs ${module_import_path})
+ endforeach()
+ endforeach()
+ if (NOT qt_all_qml_output_dirs)
+ return()
+ endif()
+
+ list(REMOVE_DUPLICATES qt_all_qml_output_dirs)
+ # lists are just strings containing semicolons;
+ # we replace them with "," to get the right format for qtconf.
+ # However, we need to add quotes to deal with whitespace
+ list(TRANSFORM qt_all_qml_output_dirs APPEND "\"")
+ list(TRANSFORM qt_all_qml_output_dirs PREPEND "\"")
+ list(JOIN qt_all_qml_output_dirs "," qt_all_qml_output_dirs)
+
+ configure_file(
+ ${__qt_qml_macros_module_base_dir}/Qt6qtconf.in ${qtconf_file}
+ @ONLY
+ )
+endfunction()
+
+
function(qt6_add_qml_module target)
set(args_option
STATIC
@@ -30,8 +153,6 @@ function(qt6_add_qml_module target)
NO_CACHEGEN
NO_RESOURCE_TARGET_PATH
NO_IMPORT_SCAN
- # TODO: Remove once all usages have also been removed
- SKIP_TYPE_REGISTRATION
ENABLE_TYPE_COMPILER
# Used to mark modules as having static side effects (i.e. if they install an image provider)
@@ -112,12 +233,6 @@ function(qt6_add_qml_module target)
)
endif()
- if(arg_SKIP_TYPE_REGISTRATION)
- message(AUTHOR_WARNING
- "SKIP_TYPE_REGISTRATION is no longer used and will be ignored."
- )
- endif()
-
# Mandatory arguments
if (NOT arg_URI)
message(FATAL_ERROR
@@ -399,53 +514,93 @@ function(qt6_add_qml_module target)
set(arg_TYPEINFO ${target}.qmltypes)
endif()
+ set(all_qml_import_paths "${arg_IMPORT_PATH}")
+ set(all_dependency_targets)
+
+ set(original_no_show_policy_value "${QT_NO_SHOW_OLD_POLICY_WARNINGS}")
+ # silent by default, we only warn if someone uses TARGET as a URI
+ set(QT_NO_SHOW_OLD_POLICY_WARNINGS TRUE)
+ __qt_internal_setup_policy(QTP0005 "6.8.0"
+ "" # intentionally empty as we silence the warning anyway
+ )
+ qt6_policy(GET QTP0005 allow_targets_for_dependencies_policy)
+ set(QT_NO_SHOW_OLD_POLICY_WARNINGS "${original_no_show_policy_value}")
+ string(COMPARE EQUAL "${allow_targets_for_dependencies_policy}" "NEW" target_is_keyword)
+
+
+ set(target_keyword_was_set FALSE)
foreach(import_set IN ITEMS IMPORTS OPTIONAL_IMPORTS DEFAULT_IMPORTS)
foreach(import IN LISTS arg_${import_set})
- string(FIND ${import} "/" slash_position REVERSE)
- if (slash_position EQUAL -1)
+ if (import STREQUAL "TARGET")
+ if (target_is_keyword)
+ set(target_keyword_was_set TRUE)
+ continue()
+ else()
+ message(AUTHOR_WARNING "TARGET is treated as a URI because QTP0005 is set to OLD. This is deprecated behavior. Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0005.html for policy details.")
+ set(target_keyword_was_set FALSE)
+ endif()
+ endif()
+ _qt_internal_parse_qml_module_dependency(${import} ${target_keyword_was_set}
+ OUTPUT_URI import_uri
+ OUTPUT_VERSION import_version
+ OUTPUT_MODULE_LOCATION module_location
+ OUTPUT_MODULE_TARGET dependency_target
+ )
+ get_filename_component(module_import_path "${module_location}" DIRECTORY)
+ list(APPEND all_qml_import_paths "${module_import_path}")
+
+ if (NOT "${import_version}" STREQUAL "")
set_property(TARGET ${target} APPEND PROPERTY
- QT_QML_MODULE_${import_set} "${import}"
+ QT_QML_MODULE_${import_set} "${import_uri} ${import_version}"
)
else()
- string(SUBSTRING ${import} 0 ${slash_position} import_module)
- math(EXPR slash_position "${slash_position} + 1")
- string(SUBSTRING ${import} ${slash_position} -1 import_version)
- if (import_version MATCHES "^([0-9]+(\\.[0-9]+)?|auto)$")
- set_property(TARGET ${target} APPEND PROPERTY
- QT_QML_MODULE_${import_set} "${import_module} ${import_version}"
- )
- else()
- message(FATAL_ERROR
- "Invalid module ${import} version number. "
- "Expected 'VersionMajor', 'VersionMajor.VersionMinor' or 'auto'."
- )
- endif()
+ set_property(TARGET ${target} APPEND PROPERTY
+ QT_QML_MODULE_${import_set} "${import_uri}"
+ )
endif()
+ if(TARGET "${dependency_target}")
+ list(APPEND all_dependency_targets "${dependency_target}")
+ endif()
+ set(target_keyword_was_set FALSE)
endforeach()
endforeach()
foreach(dependency IN LISTS arg_DEPENDENCIES)
- string(FIND ${dependency} "/" slash_position REVERSE)
- if (slash_position EQUAL -1)
+
+ if (dependency STREQUAL "TARGET")
+ if (target_is_keyword)
+ set(target_keyword_was_set TRUE)
+ continue()
+ else()
+ message(AUTHOR_WARNING "TARGET is treated as a URI because QTP0005 is set to OLD. This is deprecated behavior. Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0005.html for policy details.")
+ set(target_keyword_was_set FALSE)
+ endif()
+ endif()
+ _qt_internal_parse_qml_module_dependency(${dependency} "${target_keyword_was_set}"
+ OUTPUT_URI dep_uri
+ OUTPUT_VERSION dep_version
+ OUTPUT_MODULE_LOCATION module_location
+ OUTPUT_MODULE_TARGET dependency_target
+ )
+ get_filename_component(module_import_path "${module_location}" DIRECTORY)
+ list(APPEND all_qml_import_paths "${module_import_path}")
+ if (NOT "${dep_version}" STREQUAL "")
set_property(TARGET ${target} APPEND PROPERTY
- QT_QML_MODULE_DEPENDENCIES "${dependency}"
+ QT_QML_MODULE_DEPENDENCIES "${dep_uri} ${dep_version}"
)
else()
- string(SUBSTRING ${dependency} 0 ${slash_position} dep_module_uri)
- math(EXPR slash_position "${slash_position} + 1")
- string(SUBSTRING ${dependency} ${slash_position} -1 dep_version)
- if (dep_version MATCHES "^([0-9]+(\\.[0-9]+)?|auto)$")
- set_property(TARGET ${target} APPEND PROPERTY
- QT_QML_MODULE_DEPENDENCIES "${dep_module_uri} ${dep_version}"
- )
- else()
- message(FATAL_ERROR
- "Invalid module dependency version number. "
- "Expected 'VersionMajor', 'VersionMajor.VersionMinor' or 'auto'."
- )
- endif()
+ set_property(TARGET ${target} APPEND PROPERTY
+ QT_QML_MODULE_DEPENDENCIES "${dep_uri}"
+ )
+ endif()
+ set(target_keyword_was_set FALSE)
+ if(TARGET "${dependency_target}")
+ list(APPEND all_dependency_targets "${dependency_target}")
endif()
endforeach()
+ ### TODO: add support for transitive dependencies, too
+ list(REMOVE_DUPLICATES all_dependency_targets)
+ set_property(TARGET ${target} PROPERTY QT_QML_DEPENDENT_QML_MODULE_TARGETS "${all_dependency_targets}")
_qt_internal_collect_qml_module_dependencies(${target})
if(arg_AUTO_RESOURCE_PREFIX)
@@ -491,6 +646,8 @@ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details."
endif()
endif()
+ list(REMOVE_DUPLICATES all_qml_import_paths)
+
set_target_properties(${target} PROPERTIES
QT_QML_MODULE_NO_LINT "${arg_NO_LINT}"
QT_QML_MODULE_NO_CACHEGEN "${arg_NO_CACHEGEN}"
@@ -520,7 +677,7 @@ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details."
QT_QML_MODULE_PAST_MAJOR_VERSIONS "${arg_PAST_MAJOR_VERSIONS}"
# TODO: Check how this is used by qt6_android_generate_deployment_settings()
- QT_QML_IMPORT_PATH "${arg_IMPORT_PATH}"
+ QT_QML_IMPORT_PATH "${all_qml_import_paths}"
)
if(arg_TYPEINFO)
@@ -756,7 +913,7 @@ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details."
cmake_language(DEFER GET_CALL qmlls_ini_generation_id call)
if("${call}" STREQUAL "")
cmake_language(EVAL CODE
- "cmake_language(DEFER ID qmlls_ini_generation_id CALL _qt_internal_write_deferred_qmlls_ini_file)"
+ "cmake_language(DEFER ID qmlls_ini_generation_id CALL _qt_internal_write_deferred_qmlls_ini_file ${target})"
)
endif()
else()
@@ -767,9 +924,91 @@ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details."
endif()
endif()
endif()
+
+ if((backing_target_type STREQUAL "EXECUTABLE") AND (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.19.0"))
+ set_property(
+ DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ APPEND
+ PROPERTY QT_QML_TARGETS_FOR_DEFERRED_QTCONF_WRITEOUT
+ ${target}
+ )
+ get_directory_property(is_qtconf_writeout_scheduled DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} QT_QML_BUILDDIR_QTCONF_DEFERRED)
+ if (NOT is_qtconf_writeout_scheduled)
+ set_property(
+ DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ PROPERTY QT_QML_BUILDDIR_QTCONF_DEFERRED TRUE
+ )
+
+ cmake_language(EVAL CODE "
+ cmake_language(DEFER DIRECTORY [[${PROJECT_SOURCE_DIR}]]
+ CALL _qt_internal_write_deferred_builddir_qtconf [[${CMAKE_CURRENT_BINARY_DIR}]])
+ ")
+ endif()
+ endif()
+
+ if("${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.19.0" AND NOT CMAKE_GENERATOR STREQUAL "Xcode")
+ set(id qmlaotstats_aggregation)
+ cmake_language(DEFER DIRECTORY ${PROJECT_BINARY_DIR} GET_CALL ${id} call)
+
+ if("${call}" STREQUAL "")
+ cmake_language(EVAL CODE "cmake_language(DEFER DIRECTORY ${PROJECT_BINARY_DIR} "
+ "ID ${id} CALL _qt_internal_deferred_aggregate_aotstats_files ${target})")
+ endif()
+ else()
+ if(NOT TARGET all_aotstats)
+ if(CMAKE_GENERATOR STREQUAL "Xcode") #TODO: QTBUG-125995
+ add_custom_target(
+ all_aotstats
+ ${CMAKE_COMMAND} -E echo "aotstats is not supported on Xcode"
+ )
+ else()
+ add_custom_target(
+ all_aotstats
+ ${CMAKE_COMMAND} -E echo "aotstats is not supported on CMake versions < 3.19"
+ )
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function(_qt_internal_deferred_aggregate_aotstats_files target)
+ get_property(module_aotstats_files GLOBAL PROPERTY "module_aotstats_files")
+ list(JOIN module_aotstats_files "\n" lines)
+ set(aotstats_list_file "${PROJECT_BINARY_DIR}/.rcc/qmlcache/all_aotstats.aotstatslist")
+ file(WRITE ${aotstats_list_file} ${lines})
+
+ set(all_aotstats_file ${PROJECT_BINARY_DIR}/.rcc/qmlcache/all_aotstats.aotstats)
+ set(formatted_stats_file ${PROJECT_BINARY_DIR}/.rcc/qmlcache/all_aotstats.txt)
+
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ add_custom_command(
+ OUTPUT
+ ${all_aotstats_file}
+ ${formatted_stats_file}
+ DEPENDS ${module_aotstats_files}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Qt6::qmlaotstats>
+ aggregate
+ ${aotstats_list_file}
+ ${all_aotstats_file}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Qt6::qmlaotstats>
+ format
+ ${all_aotstats_file}
+ ${formatted_stats_file}
+ )
+
+ if(NOT TARGET all_aotstats)
+ add_custom_target(all_aotstats
+ DEPENDS ${formatted_stats_file}
+ COMMAND ${CMAKE_COMMAND} -E cat ${formatted_stats_file}
+ )
+ endif()
endfunction()
-function(_qt_internal_write_deferred_qmlls_ini_file)
+function(_qt_internal_write_deferred_qmlls_ini_file target)
set(qmlls_ini_file "${CMAKE_CURRENT_SOURCE_DIR}/.qmlls.ini")
get_directory_property(_qmlls_ini_build_folders _qmlls_ini_build_folders)
list(REMOVE_DUPLICATES _qmlls_ini_build_folders)
@@ -780,8 +1019,11 @@ function(_qt_internal_write_deferred_qmlls_ini_file)
# cmake list separator and windows path separator are both ';', so no replacement needed
set(concatenated_build_dirs "${_qmlls_ini_build_folders}")
endif()
- set(file_content "[General]\nbuildDir=${concatenated_build_dirs}\nno-cmake-calls=false\n")
+ set(file_content "[General]\n")
+ string(APPEND file_content "buildDir=${concatenated_build_dirs}\n")
+ string(APPEND file_content "no-cmake-calls=false\n")
file(CONFIGURE OUTPUT "${qmlls_ini_file}" CONTENT "${file_content}")
+ _add_documentation_path_to_qmlls_ini_file(${target} ${qmlls_ini_file})
endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
@@ -794,6 +1036,35 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
endfunction()
endif()
+function(_add_documentation_path_to_qmlls_ini_file target qmlls_ini_file)
+ get_target_property(qtpaths ${QT_CMAKE_EXPORT_NAMESPACE}::qtpaths LOCATION)
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ set(docPath "${CMAKE_CURRENT_BINARY_DIR}/.docPath.tmp")
+ add_custom_command(
+ OUTPUT
+ ${docPath}
+ COMMAND
+ ${CMAKE_COMMAND} -E echo_append "docDir=" >> ${docPath};
+ COMMAND
+ ${tool_wrapper}
+ ${qtpaths}
+ --query QT_INSTALL_DOCS >> ${docPath}
+ COMMENT "Querying Qt documentation path"
+ VERBATIM
+ )
+ add_custom_target(${target}_custom ALL
+ DEPENDS ${docPath}
+ COMMAND
+ ${CMAKE_COMMAND} -E cat ${docPath} >> ${qmlls_ini_file}
+ COMMAND
+ ${CMAKE_COMMAND} -E rm -rf -- ${docPath}
+ COMMENT "Adding Qt documentation path to .qmlls.ini"
+ VERBATIM
+ )
+ add_dependencies(${target} ${target}_custom)
+
+endfunction()
+
# Make the prefix conform to the following:
# - Starts with a "/"
# - Does not end with a "/" unless the prefix is exactly "/"
@@ -2403,6 +2674,8 @@ function(qt6_target_qml_sources target)
"$<${have_direct_calls}:--direct-calls>"
"$<${have_arguments}:${arguments}>"
${qrc_resource_args}
+ "--dump-aot-stats"
+ "--module-id=${arg_URI}(${target})"
)
# For direct evaluation in if() below
@@ -2613,6 +2886,17 @@ function(qt6_target_qml_sources target)
set_property(TARGET ${target} APPEND_STRING PROPERTY
_qt_internal_qmldir_content "${qmldir_file_contents}"
)
+
+ if(ANDROID AND QT_ANDROID_GENERATE_JAVA_QML_COMPONENTS)
+ get_source_file_property(qml_file_generate_java_classes ${qml_file_src}
+ QT_QML_GENERATE_JAVA_CLASS
+ )
+ if(qml_file_generate_java_classes)
+ get_target_property(qml_module_uri ${target} QT_QML_MODULE_URI)
+ set_property(TARGET ${target} APPEND PROPERTY
+ _qt_qml_files_for_java_generator "${qml_module_uri}.${qml_file_typename}")
+ endif()
+ endif()
endif()
endif()
@@ -2649,9 +2933,17 @@ function(qt6_target_qml_sources target)
set(qmlcachegen_cmd "${qmlcachegen}")
endif()
+ set(aotstats_file "")
+ if("${qml_file_src}" MATCHES ".+\\.qml")
+ set(aotstats_file "${compiled_file}.aotstats")
+ list(APPEND aotstats_files ${aotstats_file})
+ endif()
+
_qt_internal_get_tool_wrapper_script_path(tool_wrapper)
add_custom_command(
- OUTPUT ${compiled_file}
+ OUTPUT
+ ${compiled_file}
+ ${aotstats_file}
COMMAND ${CMAKE_COMMAND} -E make_directory ${out_dir}
COMMAND
${tool_wrapper}
@@ -2695,6 +2987,29 @@ function(qt6_target_qml_sources target)
endif()
endforeach()
+ if(NOT "${arg_URI}" STREQUAL "")
+ list(JOIN aotstats_files "\n" aotstats_files_lines)
+ set(module_aotstats_list_file "${CMAKE_CURRENT_BINARY_DIR}/.rcc/qmlcache/module_${arg_URI}.aotstatslist")
+ file(WRITE ${module_aotstats_list_file} ${aotstats_files_lines})
+
+ # Aggregate qml file aotstats into module-level aotstats
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ set(output "${CMAKE_CURRENT_BINARY_DIR}/.rcc/qmlcache/module_${arg_URI}.aotstats")
+ add_custom_command(
+ OUTPUT ${output}
+ DEPENDS ${aotstats_files}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Qt6::qmlaotstats>
+ aggregate
+ ${module_aotstats_list_file}
+ ${output}
+ )
+
+ # Collect module-level aotstats files for later aggregation at the project level
+ set_property(GLOBAL APPEND PROPERTY "module_aotstats_files" ${output})
+ endif()
+
if(ANDROID)
_qt_internal_collect_qml_root_paths("${target}" ${arg_QML_FILES})
endif()
@@ -3825,9 +4140,30 @@ endif()")
# imports deployed to the bundle anyway, the build RPATHs will allow
# the regular libraries, frameworks and non-QML plugins to still be
# found, even if they are outside the app bundle.
+
+ # Support Xcode, which places the application build dir into a configuration specific
+ # subdirectory. Override both the deploy prefix and install prefix, because we
+ # differentiate them in the qml installation implementation due to ENV{DESTDIR}
+ # handling.
+ set(deploy_path_suffix "")
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi_config)
+ set(deploy_path_suffix "/$<CONFIG>")
+ endif()
+
+ set(target_binary_dir_with_config_prefix
+ "$<TARGET_PROPERTY:${arg_TARGET},BINARY_DIR>${deploy_path_suffix}")
+
+ set(post_build_install_prefix
+ "CMAKE_INSTALL_PREFIX=${target_binary_dir_with_config_prefix}")
+
+ set(post_build_deploy_prefix
+ "QT_DEPLOY_PREFIX=${target_binary_dir_with_config_prefix}")
+
add_custom_command(TARGET ${arg_TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND}
- -D "QT_DEPLOY_PREFIX=$<TARGET_PROPERTY:${arg_TARGET},BINARY_DIR>"
+ -D "${post_build_install_prefix}"
+ -D "${post_build_deploy_prefix}"
-D "__QT_DEPLOY_IMPL_DIR=${deploy_impl_dir}"
-D "__QT_DEPLOY_POST_BUILD=TRUE"
-P "${post_build_deploy_script}"
diff --git a/src/qml/Qt6qt.conf.in b/src/qml/Qt6qt.conf.in
new file mode 100644
index 0000000000..10a7dcab50
--- /dev/null
+++ b/src/qml/Qt6qt.conf.in
@@ -0,0 +1,5 @@
+[Paths]
+QmlImports = @qt_all_qml_output_dirs@
+
+[Config]
+MergeQtConf = true
diff --git a/src/qml/common/qv4alloca_p.h b/src/qml/common/qv4alloca_p.h
index c1d1e6e87d..51c99192d3 100644
--- a/src/qml/common/qv4alloca_p.h
+++ b/src/qml/common/qv4alloca_p.h
@@ -17,16 +17,17 @@
#include <QtCore/private/qglobal_p.h>
-#if QT_CONFIG(alloca_h)
+#include <stdlib.h>
+#if __has_include(<alloca.h>)
# include <alloca.h>
-#elif QT_CONFIG(alloca_malloc_h)
+#endif
+#if __has_include(<malloc.h>)
# include <malloc.h>
+#endif
+
+#ifdef Q_CC_MSVC
// This does not matter unless compiling in strict standard mode.
-# ifdef Q_CC_MSVC
-# define alloca _alloca
-# endif
-#else
-# include <stdlib.h>
+# define alloca _alloca
#endif
// Define Q_ALLOCA_VAR macro to be used instead of #ifdeffing
@@ -37,7 +38,7 @@
Q_ALLOCA_DECLARE(type, name); \
Q_ALLOCA_ASSIGN(type, name, size)
-#if QT_CONFIG(alloca)
+#ifdef alloca
#define Q_ALLOCA_DECLARE(type, name) \
type *name = 0
@@ -46,27 +47,16 @@
name = static_cast<type*>(alloca(size))
#else
-QT_BEGIN_NAMESPACE
-class Qt_AllocaWrapper
-{
-public:
- Qt_AllocaWrapper() { m_data = 0; }
- ~Qt_AllocaWrapper() { free(m_data); }
- void *data() { return m_data; }
- void allocate(int size) { m_data = malloc(size); memset(m_data, 0, size); }
-private:
- void *m_data;
-};
-QT_END_NAMESPACE
+# include <memory>
#define Q_ALLOCA_DECLARE(type, name) \
- Qt_AllocaWrapper _qt_alloca_##name; \
+ std::unique_ptr<char[]> _qt_alloca_##name; \
type *name = nullptr
#define Q_ALLOCA_ASSIGN(type, name, size) \
do { \
- _qt_alloca_##name.allocate(size); \
- name = static_cast<type*>(_qt_alloca_##name.data()); \
+ _qt_alloca_##name.reset(new char[size]); \
+ name = reinterpret_cast<type*>(_qt_alloca_##name.get()); \
} while (false)
#endif
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index 79df230872..c21fc19fa9 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -1227,6 +1227,7 @@ struct Unit
NativeMethodsAcceptThisObject = 0x800,
ValueTypesCopied = 0x1000,
ValueTypesAddressable = 0x2000,
+ ValueTypesAssertable = 0x4000,
};
quint32_le flags;
quint32_le stringTableSize;
@@ -1706,6 +1707,11 @@ public:
return unitData()->flags & CompiledData::Unit::ValueTypesAddressable;
}
+ bool valueTypesAreAssertable() const
+ {
+ return unitData()->flags & CompiledData::Unit::ValueTypesAssertable;
+ }
+
bool componentsAreBound() const
{
return unitData()->flags & CompiledData::Unit::ComponentsBound;
diff --git a/src/qml/common/qv4staticvalue_p.h b/src/qml/common/qv4staticvalue_p.h
index e887cdc674..9b4f582c00 100644
--- a/src/qml/common/qv4staticvalue_p.h
+++ b/src/qml/common/qv4staticvalue_p.h
@@ -366,10 +366,10 @@ struct StaticValue
QV4_NEARLY_ALWAYS_INLINE void setDouble(double d) {
if (qt_is_nan(d)) {
// We cannot store just any NaN. It has to be a NaN with only the quiet bit
- // set in the upper bits of the mantissa and the sign bit off.
+ // set in the upper bits of the mantissa and the sign bit either on or off.
// qt_qnan() happens to produce such a thing via std::numeric_limits,
// but this is actually not guaranteed. Therefore, we make our own.
- _val = (quint64(QuickType::NaN) << Tag_Shift);
+ _val = (quint64(std::signbit(d) ? QuickType::MinusNaN : QuickType::NaN) << Tag_Shift);
Q_ASSERT(isNaN());
} else {
memcpy(&_val, &d, 8);
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index a81f8fb1d8..72111b3138 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -861,6 +861,15 @@ private:
return true;
}
+ if (value == "Inassertable"_L1) {
+ setFlag(Pragma::Assertable, false);
+ return true;
+ }
+ if (value == "Assertable"_L1) {
+ setFlag(Pragma::Assertable, true);
+ return true;
+ }
+
return false;
});
}
@@ -1718,6 +1727,10 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
.testFlag(Pragma::Addressable)) {
createdUnit->flags |= Unit::ValueTypesAddressable;
}
+ if (Pragma::ValueTypeBehaviorValues(p->valueTypeBehavior)
+ .testFlag(Pragma::Assertable)) {
+ createdUnit->flags |= Unit::ValueTypesAssertable;
+ }
break;
case Pragma::Translator:
if (createdUnit->translationTableSize)
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 546d1fac58..ffd3ad72f7 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -443,6 +443,7 @@ struct Q_QML_COMPILER_EXPORT Pragma
{
Copy = 0x1,
Addressable = 0x2,
+ Assertable = 0x4,
};
Q_DECLARE_FLAGS(ValueTypeBehaviorValues, ValueTypeBehaviorValue);
diff --git a/src/qml/configure.cmake b/src/qml/configure.cmake
index d1ff90bd54..1bc647ff29 100644
--- a/src/qml/configure.cmake
+++ b/src/qml/configure.cmake
@@ -14,7 +14,7 @@ qt_find_package(LTTngUST PROVIDED_TARGETS LTTng::UST MODULE_NAME qml QMAKE_LIB l
qt_find_package(Python REQUIRED)
if(Python_Interpreter_FOUND)
# Need to make it globally available to the project
- set(QT_INTERNAL_DECLARATIVE_PYTHON "${Python_EXECUTABLE}" CACHE STRING "")
+ set(QT_INTERNAL_DECLARATIVE_PYTHON "${Python_EXECUTABLE}" CACHE STRING "" FORCE)
endif()
#### Tests
diff --git a/src/qml/doc/src/cmake/cmake-properties.qdoc b/src/qml/doc/src/cmake/cmake-properties.qdoc
index 297a094582..a2ca59efc8 100644
--- a/src/qml/doc/src/cmake/cmake-properties.qdoc
+++ b/src/qml/doc/src/cmake/cmake-properties.qdoc
@@ -206,3 +206,24 @@ C++ during qmltc compilation.
\sa{qmltc-cmake}
*/
+
+/*!
+\page cmake-source-file-property-qt-qml-generate-java-class.html
+\ingroup cmake-source-file-properties-qtqml
+\ingroup cmake-android-build-properties
+
+\title QT_QML_GENERATE_JAVA_CLASS
+
+\summary {Marks a QML file for Java code generation.}
+
+\cmakepropertysince 6.8
+When using QML as a \l {Android: View} in Android via \l QtQuickView, you can choose
+the QML components to make available as generated Java classes usable from Android code.
+To mark a \c {.qml} file for code generation, set its \c QT_QML_GENERATE_JAVA_CLASS
+source property to \c TRUE. The source property must be set before
+\l {qt_add_qml_module}{creating} the module. The file should start with an uppercase
+letter and define a QML component. This property is valid only if
+\l QT_ANDROID_GENERATE_JAVA_QML_COMPONENTS is defined.
+
+\sa {Naming Custom QML Object Types}
+*/
diff --git a/src/qml/doc/src/cmake/policy/qtp0005.qdoc b/src/qml/doc/src/cmake/policy/qtp0005.qdoc
new file mode 100644
index 0000000000..25d5175789
--- /dev/null
+++ b/src/qml/doc/src/cmake/policy/qtp0005.qdoc
@@ -0,0 +1,42 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-cmake-policy-qtp0005.html
+\ingroup qt-cmake-policies
+
+\title QTP0005
+\keyword qt_cmake_policy_qtp0005
+
+\summary {qt_add_qml_module's DEPENDENCIES argument accepts targets}
+
+This policy was introduced in Qt 6.8. It allows passing targets to
+\l{qt_add_qml_module}{qt_add_qml_module()} \c DEPENDENCIES, \c IMPORTS, \c
+OPTIONAL_IMPORTS and \c DEFAULT_IMPORTS.
+
+Enabling this policy means that the arguments which are passed to the key words
+can be prefixed with TARGET, and are then treated as a target name.
+
+The \c OLD behavior of this policy is that the "TARGET name" is treated as two
+URIs, "TARGET" and "name".
+
+The \c NEW behavior of this policy is that \c TARGET is considered a keyword,
+and the URI is extracted from the target which follows next. It is a hard error
+if the name following \c TARGET does not name a target, or if that target does
+not correspond to a QML module.
+
+In both the \c NEW and the \c OLD behavior it is possible to specify a module
+version by appending a slash and the version. See
+\l{Declaring module dependencies} for more details.
+
+Qt 6.8 issues warnings if you pass a URI to \c DEPENDENCIES which coincides
+with a target name.
+Use the \l qt_policy command to suppress the warning by explicitly setting
+the policy to \c OLD or \c NEW.
+
+\qtpolicydeprecatedbehavior
+
+\sa qt_policy, {qt6_standard_project_setup}{qt_standard_project_setup()},
+ qt_cmake_policies, qt_add_qml_module
+
+*/
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 4ca7635b9c..63f9707d4d 100644
--- a/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
+++ b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
@@ -578,6 +578,9 @@ These additional targets are generated internally by \c{qt_add_qml_module()}
and are referenced by the backing target's linking requirements as part of
ensuring that resources are set up and loaded correctly.
+\note Since Qt 6.8, it is possible to pass a target name to IMPORTS and
+DEPENDENCIES. See \l{QTP0005} for more details.
+
\target PLUGIN_TARGET
\section2 Targets and plugin targets
diff --git a/src/qml/doc/src/external-resources.qdoc b/src/qml/doc/src/external-resources.qdoc
index 091df193a5..6ea7e4a005 100644
--- a/src/qml/doc/src/external-resources.qdoc
+++ b/src/qml/doc/src/external-resources.qdoc
@@ -69,3 +69,12 @@
\externalpage https://developer.android.com/reference/java/lang/ClassCastException
\title Android: ClassCastException
*/
+/*!
+ \externalpage https://developer.android.com/topic/libraries/view-binding
+ \title Android: View binding
+*/
+/*!
+ \externalpage https://developer.android.com/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW
+ \title Android: SYSTEM_ALERT_WINDOW
+*/
+
diff --git a/src/qml/doc/src/javascript/qmlglobalobject.qdoc b/src/qml/doc/src/javascript/qmlglobalobject.qdoc
index 15b9996ff3..1bd03fad54 100644
--- a/src/qml/doc/src/javascript/qmlglobalobject.qdoc
+++ b/src/qml/doc/src/javascript/qmlglobalobject.qdoc
@@ -13,8 +13,8 @@ additional imports:
\list
\li The \l{QmlGlobalQtObject}{Qt object}: A QML object that offers helper methods
and properties specific to the QML environment.
-\li \l {Qt::}{qsTr()}, \l {Qt::}{qsTranslate()}, \l {Qt::}{qsTrId()}, \l {Qt::}{qsTrNoOp()},
- \l {Qt::}{qsTranslateNoOp()}, \l {Qt::}{qsTrIdNoOp()} functions:
+\li \l {Qt::}{qsTr()}, \l {Qt::}{qsTranslate()}, \l {Qt::}{qsTrId()}, \l {Qt::}{QT_TR_NOOP()()},
+ \l {Qt::}{QT_TRANSLATE_NOOP()}, \l {Qt::}{QT_TRID_NOOP()} functions:
QML functions that let you translate \l{Mark Strings for Translation}
{strings} and \l{Mark Translatable Data Text Strings}{string literals} in the
QML environment.
diff --git a/src/qml/doc/src/qmllanguageref/documents/structure.qdoc b/src/qml/doc/src/qmllanguageref/documents/structure.qdoc
index 5a43ae2028..72a6e08407 100644
--- a/src/qml/doc/src/qmllanguageref/documents/structure.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/structure.qdoc
@@ -215,12 +215,6 @@ QtObject {
}
\endqml
-If the type does not match, casting returns \c undefined. \c instanceof
-only checks for inheritance, not for all possible type coercions. So, for
-example, a \l{QRect} is not a \c rect value type since \c rect is \l{QRectF}
-in C++, and therefore not related by inheritance. With \c as you can cast
-to any type compatible via coercion.
-
Since \c rect in the above example is now a type name, it will shadow any
properties called \c{rect}.
@@ -231,6 +225,25 @@ able to. You can use \l{qmllint Reference}{qmllint} to find such occurrences.
There is also a \c{Inaddressable} value you can use to explicitly specify the
default behavior.
+Another attribute to the \c{ValueTypeBehavior} pragma is \c{Assertable},
+introduced in Qt 6.8. Due to a mistake in Qt 6.6 and 6.7 the \c{a as rect} above
+not only checks whether \c{a} is a \c{rect} but also constructs a \c{rect} if
+\c{a} is of a compatible type. This is obviously not what a type assertion
+should do. Specifying \c{Assertable} prevents this behavior and restricts type
+assertions for value types to only check for the type. You should always specify
+it if you are going to use value types with \c{as}. In any case, if the
+type assertion for a value type fails, the result is \c{undefined}.
+
+\c{instanceof} does not have this problem since it only checks for inheritance,
+not for all possible type coercions.
+
+\note Using \c{as} with the \c{int} and \c{double} types is not advisable since by
+JavaScript rules, the result of any calculation is a floating point number, even
+if it happens to hold the same value as its integer equivalent. Conversely, any
+integer constant you declare in JavaScript is not a double by QML's type mapping
+rules. Furthermore, \c{int} and \c{double} are reserved words. You can only
+address these types via type namespaces.
+
Value types and sequences are generally treated as references. This means, if
you retrieve a value type instance from a property into a local value, and then
change the local value, the original property is also changed. Furthermore,
diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
index 0fb7d5f039..2b1803042e 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
@@ -868,7 +868,7 @@ provided by the client:
SquareButton {
onDeactivated: console.log("Deactivated!")
onActivated: (xPosition, yPosition) => {
- console.log(`Activated at {xPosition}, ${yPosition}`)
+ console.log(`Activated at ${xPosition}, ${yPosition}`)
}
}
\endqml
diff --git a/src/qml/doc/src/qmlsingletons.qdoc b/src/qml/doc/src/qmlsingletons.qdoc
index ad441eca85..e5c95d4178 100644
--- a/src/qml/doc/src/qmlsingletons.qdoc
+++ b/src/qml/doc/src/qmlsingletons.qdoc
@@ -20,7 +20,7 @@ the singleton in a QML file, or register it from C++.
\section2 Defining singletons in QML
To define a singleton in QML, you first have to add
\code
-pragma singleton
+pragma Singleton
\endcode
to the top of your file.
There's one more step: You will need to add an entry to the QML module's
diff --git a/src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc b/src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc
index 28d2683ff9..836acc3f6a 100644
--- a/src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc
+++ b/src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc
@@ -1,4 +1,4 @@
-// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
@@ -7,11 +7,86 @@
\brief The SVG to QML converter tool
\ingroup qtqml-tooling
-svgtoqml is a command line tool shipped with Qt that converts an SVG document
+\c svgtoqml is a command line tool shipped with Qt that converts an SVG document
to a QML file. This QML file can then be used as a component in Qt Quick
-applications.
+applications. The \l{Weather Forecast Example} includes multiple QML files that have been generated
+using this tool.
-\note svgtoqml is currently in a Tech Preview stage. It only supports
-a limited subset of what the QtSvg module supports.
+\section1 Overview
+The \c svgtoqml will convert an SVG file to a QML file which uses Qt Quick primitives. Since
+Qt Quick supports scalable vector graphics, the resulting item will be smoothly transformable as far
+as this is possible. As a baseline, the tool supports most of the static features of the SVG Tiny 1.2
+profile. Certain additional features are supported, determined on a case-by-case basis. Interactive
+features and animations are not supported.
+
+\section1 Usage
+The basic usage of \c svgtoqml is to provide an input file and an output file:
+\c{svgtoqml input.svg output.qml}. This will read the \c{input.svg} file and convert it into the
+corresponding Qt Quick scene in \c{output.qml}, which can then be used as part of a Qt Quick
+application.
+
+In addition, it supports the following options:
+
+\table
+\header
+ \li Option
+ \li Description
+\row
+ \li --copyright-statement <string>
+ \li Adds <string> as a comment at the beginning of the generated file.
+\row
+ \li --curve-renderer
+ \li Enables the curve renderer backend for \l{Qt Quick Shapes}. This enables smooth, antialiased
+ shapes in the scene without multi-sampling, but at some extra cost.
+\row
+ \li --optimize-paths
+ \li Enables optimization of paths before committing them to the QML file, potentially making
+ them faster to load and render later.
+\row
+ \li --outline-stroke-mode
+ \li Stroke the outline (contour) of the filled shape instead of the original path.
+\row
+ \li -t, --type-name <string>
+ \li In place of \l{Shape}, the output will use the type name <string> instead. This is
+ enables using a custom item to override the default behavior of \l{Shape} items.
+\row
+ \li -v, --view
+ \li Display a preview of the Qt Quick item as it will be generated.
+\endtable
+
+\section1 Comparison to other options
+There are multiple options for including SVG content in Qt Quick. The following will give an
+overview of where \c svgtoqml fits into the story.
+
+\section2 Comparison to Qt Svg
+\l{Qt Svg} is a module which provides a parser and software renderer for SVG files. In addition, it
+includes an image loader plugin, so that SVG files can be loaded directly by the \l{Image} element
+in Qt Quick. The SVG will then be rasterized and cached at a specified size and redrawing it will
+be quite cheap. But zooming into the image without pixelation will involve reloading it at a
+different size, which in turn can be expensive.
+
+\c svgtoqml (and the \l{VectorImage} component) are alternative ways of rendering the same content.
+Once loaded into Qt Quick, transforms can be changed while retaining the geometry data needed to
+render the scene in GPU memory. Thus, the vector image can be redrawn at different scales with very
+little overhead.
+
+If the image size will not change during the life time of the application, however, loading the
+SVG as an \l{Image} will be more efficient. In this case, if the SVG is always rendered at a
+small subset of possible sizes, consider pre-rasterizing it to an image format which is more
+efficient to load, such as \c PNG.
+
+\section2 Comparison to VectorImage
+The \l{VectorImage} component provides the same basic functionality as \c svgtoqml, but instead of
+pregenerating the Qt Quick scene as a QML file, it creates the scene at runtime. This allows loading
+SVG files that are not provided at build time and thus allows for more flexibility. Pregenerating
+the scenes with \c svgtoqml allows optimizing the scene before it is loaded. Thus, for files that
+are available at build time, \c svgtoqml is the preferred option.
+
+\section2 Comparison to PathSvg
+The \l{PathSvg} component is part of the \l{Qt Quick Shapes} module. It provides a way to define
+paths with the syntax used by SVG, where the control points of a path are specified as a string. It
+does not support loading SVG files, so it is not a direct alternative to \c svgtoqml. If a complex
+SVG contains a specific shape needed by the application, then copying this path description into
+\l{PathSvg} may be more convenient than generating the full file.
*/
diff --git a/src/qml/jsapi/qjsprimitivevalue.h b/src/qml/jsapi/qjsprimitivevalue.h
index 4ba3fd7dc3..3551eca358 100644
--- a/src/qml/jsapi/qjsprimitivevalue.h
+++ b/src/qml/jsapi/qjsprimitivevalue.h
@@ -355,11 +355,16 @@ public:
return leftInt % rightInt;
Q_FALLTHROUGH();
}
- default:
+ case Undefined:
+ case Null:
+ case Double:
+ case String:
break;
}
Q_FALLTHROUGH();
- default:
+ case Undefined:
+ case Double:
+ case String:
break;
}
@@ -706,9 +711,18 @@ private:
{
switch (type()) {
case Undefined: return true;
+ case Null: return false;
+ case Boolean: return false;
+ case Integer: return false;
case Double: return std::isnan(asDouble());
- default: return false;
+ case String: return false;
}
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+ #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ Q_UNREACHABLE_RETURN(false);
+ #else
+ return false;
+ #endif
}
struct QJSPrimitiveValuePrivate
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
index f2be552cf8..a49bd32d66 100644
--- a/src/qml/jsruntime/qv4arraybuffer.cpp
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -12,14 +12,14 @@ DEFINE_OBJECT_VTABLE(ArrayBufferCtor);
DEFINE_OBJECT_VTABLE(SharedArrayBuffer);
DEFINE_OBJECT_VTABLE(ArrayBuffer);
-void Heap::SharedArrayBufferCtor::init(QV4::ExecutionContext *scope)
+void Heap::SharedArrayBufferCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("SharedArrayBuffer"));
+ Heap::FunctionObject::init(engine, QStringLiteral("SharedArrayBuffer"));
}
-void Heap::ArrayBufferCtor::init(QV4::ExecutionContext *scope)
+void Heap::ArrayBufferCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("ArrayBuffer"));
+ Heap::FunctionObject::init(engine, QStringLiteral("ArrayBuffer"));
}
ReturnedValue SharedArrayBufferCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
index aafa3c6335..af1195a947 100644
--- a/src/qml/jsruntime/qv4arraybuffer_p.h
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -25,11 +25,11 @@ namespace QV4 {
namespace Heap {
struct SharedArrayBufferCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
struct ArrayBufferCtor : SharedArrayBufferCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
struct Q_QML_EXPORT SharedArrayBuffer : Object {
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index e1da807c21..724f6fbfa3 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -630,11 +630,6 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
if (!arrayData || !arrayData->length())
return;
- if (!comparefn.isUndefined() && !comparefn.isFunctionObject()) {
- engine->throwTypeError();
- return;
- }
-
// The spec says the sorting goes through a series of get,put and delete operations.
// this implies that the attributes don't get sorted around.
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index a32017210a..40a7123232 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -14,9 +14,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ArrayCtor);
-void Heap::ArrayCtor::init(QV4::ExecutionContext *scope)
+void Heap::ArrayCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Array"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Array"));
}
ReturnedValue ArrayCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -848,15 +848,69 @@ ReturnedValue ArrayPrototype::method_slice(const FunctionObject *b, const Value
ReturnedValue ArrayPrototype::method_sort(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
+ // Based on https://tc39.es/ecma262/#sec-array.prototype.sort
+
Scope scope(b);
+
+ ScopedValue comparefn(scope, argc ? argv[0] : Value::undefinedValue());
+
+ // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
+ if (!comparefn->isUndefined() && !comparefn->isFunctionObject())
+ return scope.engine->throwTypeError(QStringLiteral("The provided comparison function is not callable."));
+
+ // 2. Let obj be ? ToObject(this value).
ScopedObject instance(scope, thisObject->toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
+ // 3. Let len be ? LengthOfArrayLike(obj).
uint len = instance->getLength();
- ScopedValue comparefn(scope, argc ? argv[0] : Value::undefinedValue());
- ArrayData::sort(scope.engine, instance, comparefn, len);
+ if (instance->arrayData() && instance->arrayData()->length()) {
+ ArrayData::sort(scope.engine, instance, comparefn, len);
+ } else {
+ // Generic implementation that does not require a populated
+ // ArrayData, this is used, for example, by `Sequences` which
+ // store their data in a different way.
+
+ // 5. Let sortedList be ? SortIndexedProperties(obj, len, SortCompare, skip-holes)
+ Value* sorted = scope.alloc(scope.engine->safeForAllocLength(len));
+ CHECK_EXCEPTION();
+
+ uint written = 0;
+ for (uint index = 0; index < len; ++index) {
+ bool hasProperty = false;
+ auto element = instance->get(index, &hasProperty);
+
+ if (hasProperty) {
+ sorted[written] = element;
+ ++written;
+ }
+ }
+
+ std::stable_sort(sorted, sorted + written, ArrayElementLessThan(scope.engine, comparefn));
+
+ // [...]
+ // 8. Repeat, while j < itemCount,
+ // a. Perform ? Set(obj, ! ToString(𝔽(j)), sortedList[j], true).
+ // [...]
+ for (uint index = 0; index < written; ++index) {
+ instance->setIndexed(index, sorted[index], QV4::Object::DoThrowOnRejection);
+ CHECK_EXCEPTION();
+ }
+
+ // [...]
+ // 10. Repeat, while j < len,
+ // a. Perform ? DeletePropertyOrThrow(obj, ! ToString(𝔽(j))).
+ // [...]
+ while (written < len) {
+ if (!instance->deleteProperty(PropertyKey::fromArrayIndex(written)))
+ return scope.engine->throwTypeError();
+ ++written;
+ }
+ }
+
+ // 11. Return obj
return thisObject->asReturnedValue();
}
@@ -1490,4 +1544,3 @@ ReturnedValue ArrayPrototype::method_get_species(const FunctionObject *, const V
{
return thisObject->asReturnedValue();
}
-
diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h
index b07e27b24f..a68068937f 100644
--- a/src/qml/jsruntime/qv4arrayobject_p.h
+++ b/src/qml/jsruntime/qv4arrayobject_p.h
@@ -50,7 +50,7 @@ namespace QV4 {
namespace Heap {
struct ArrayCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index 3110ec7992..5c1d50e753 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -8,9 +8,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(BooleanCtor);
DEFINE_OBJECT_VTABLE(BooleanObject);
-void Heap::BooleanCtor::init(QV4::ExecutionContext *scope)
+void Heap::BooleanCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Boolean"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Boolean"));
}
ReturnedValue BooleanCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index e009b0413a..1b2d3914ac 100644
--- a/src/qml/jsruntime/qv4booleanobject_p.h
+++ b/src/qml/jsruntime/qv4booleanobject_p.h
@@ -25,7 +25,7 @@ namespace QV4 {
namespace Heap {
struct BooleanCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 3ae3e5d24c..01f9b4adf3 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -32,7 +32,7 @@ Heap::CallContext *ExecutionContext::newBlockContext(CppStackFrame *frame, int b
Heap::ExecutionContext *outer = static_cast<Heap::ExecutionContext *>(frame->context()->m());
c->outer.set(v4, outer);
if (frame->isJSTypesFrame()) {
- c->function.set(v4, static_cast<Heap::FunctionObject *>(
+ c->function.set(v4, static_cast<Heap::JavaScriptFunctionObject *>(
Value::fromStaticValue(
static_cast<JSTypesStackFrame *>(frame)->jsFrame->function).m()));
} else {
@@ -74,7 +74,7 @@ Heap::CallContext *ExecutionContext::newCallContext(JSTypesStackFrame *frame)
c->init();
c->outer.set(v4, outer);
- c->function.set(v4, static_cast<Heap::FunctionObject *>(
+ c->function.set(v4, static_cast<Heap::JavaScriptFunctionObject *>(
Value::fromStaticValue(frame->jsFrame->function).m()));
const CompiledData::Function *compiledFunction = function->compiledFunction;
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 82a9472223..48b6e04025 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -64,7 +64,7 @@ Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == 0);
Q_STATIC_ASSERT(offsetof(ExecutionContextData, activation) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE);
#define CallContextMembers(class, Member) \
- Member(class, Pointer, FunctionObject *, function) \
+ Member(class, Pointer, JavaScriptFunctionObject *, function) \
Member(class, ValueArray, ValueArray, locals)
DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) {
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index f4ca09a127..689eb9232b 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -13,9 +13,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(DataViewCtor);
DEFINE_OBJECT_VTABLE(DataView);
-void Heap::DataViewCtor::init(QV4::ExecutionContext *scope)
+void Heap::DataViewCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("DataView"));
+ Heap::FunctionObject::init(engine, QStringLiteral("DataView"));
}
static uint toIndex(ExecutionEngine *e, const Value &v)
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index ab2e1e589a..b5fa41d964 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -24,7 +24,7 @@ namespace QV4 {
namespace Heap {
struct DataViewCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
#define DataViewMembers(class, Member) \
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 6b64be3abb..2cb020e495 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -766,9 +766,9 @@ QDate DateObject::dateTimeToDate(const QDateTime &dateTime)
DEFINE_OBJECT_VTABLE(DateCtor);
-void Heap::DateCtor::init(QV4::ExecutionContext *scope)
+void Heap::DateCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Date"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Date"));
}
ReturnedValue DateCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index 7debcff4e9..4c184de897 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -189,7 +189,7 @@ private:
struct DateCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index a2a2e99a01..6754c3c887 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -627,25 +627,23 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this));
jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(ic->d()));
- ExecutionContext *global = rootContext();
-
- jsObjects[Object_Ctor] = memoryManager->allocate<ObjectCtor>(global);
- jsObjects[String_Ctor] = memoryManager->allocate<StringCtor>(global);
- jsObjects[Symbol_Ctor] = memoryManager->allocate<SymbolCtor>(global);
- jsObjects[Number_Ctor] = memoryManager->allocate<NumberCtor>(global);
- jsObjects[Boolean_Ctor] = memoryManager->allocate<BooleanCtor>(global);
- jsObjects[Array_Ctor] = memoryManager->allocate<ArrayCtor>(global);
- jsObjects[Function_Ctor] = memoryManager->allocate<FunctionCtor>(global);
- jsObjects[GeneratorFunction_Ctor] = memoryManager->allocate<GeneratorFunctionCtor>(global);
- jsObjects[Date_Ctor] = memoryManager->allocate<DateCtor>(global);
- jsObjects[RegExp_Ctor] = memoryManager->allocate<RegExpCtor>(global);
- jsObjects[Error_Ctor] = memoryManager->allocate<ErrorCtor>(global);
- jsObjects[EvalError_Ctor] = memoryManager->allocate<EvalErrorCtor>(global);
- jsObjects[RangeError_Ctor] = memoryManager->allocate<RangeErrorCtor>(global);
- jsObjects[ReferenceError_Ctor] = memoryManager->allocate<ReferenceErrorCtor>(global);
- jsObjects[SyntaxError_Ctor] = memoryManager->allocate<SyntaxErrorCtor>(global);
- jsObjects[TypeError_Ctor] = memoryManager->allocate<TypeErrorCtor>(global);
- jsObjects[URIError_Ctor] = memoryManager->allocate<URIErrorCtor>(global);
+ jsObjects[Object_Ctor] = memoryManager->allocate<ObjectCtor>(this);
+ jsObjects[String_Ctor] = memoryManager->allocate<StringCtor>(this);
+ jsObjects[Symbol_Ctor] = memoryManager->allocate<SymbolCtor>(this);
+ jsObjects[Number_Ctor] = memoryManager->allocate<NumberCtor>(this);
+ jsObjects[Boolean_Ctor] = memoryManager->allocate<BooleanCtor>(this);
+ jsObjects[Array_Ctor] = memoryManager->allocate<ArrayCtor>(this);
+ jsObjects[Function_Ctor] = memoryManager->allocate<FunctionCtor>(this);
+ jsObjects[GeneratorFunction_Ctor] = memoryManager->allocate<GeneratorFunctionCtor>(this);
+ jsObjects[Date_Ctor] = memoryManager->allocate<DateCtor>(this);
+ jsObjects[RegExp_Ctor] = memoryManager->allocate<RegExpCtor>(this);
+ jsObjects[Error_Ctor] = memoryManager->allocate<ErrorCtor>(this);
+ jsObjects[EvalError_Ctor] = memoryManager->allocate<EvalErrorCtor>(this);
+ jsObjects[RangeError_Ctor] = memoryManager->allocate<RangeErrorCtor>(this);
+ jsObjects[ReferenceError_Ctor] = memoryManager->allocate<ReferenceErrorCtor>(this);
+ jsObjects[SyntaxError_Ctor] = memoryManager->allocate<SyntaxErrorCtor>(this);
+ jsObjects[TypeError_Ctor] = memoryManager->allocate<TypeErrorCtor>(this);
+ jsObjects[URIError_Ctor] = memoryManager->allocate<URIErrorCtor>(this);
jsObjects[IteratorProto] = memoryManager->allocate<IteratorPrototype>();
ic = newInternalClass(ForInIteratorPrototype::staticVTable(), iteratorPrototype());
@@ -663,9 +661,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
// url
//
- jsObjects[Url_Ctor] = memoryManager->allocate<UrlCtor>(global);
+ jsObjects[Url_Ctor] = memoryManager->allocate<UrlCtor>(this);
jsObjects[UrlProto] = memoryManager->allocate<UrlPrototype>();
- jsObjects[UrlSearchParams_Ctor] = memoryManager->allocate<UrlSearchParamsCtor>(global);
+ jsObjects[UrlSearchParams_Ctor] = memoryManager->allocate<UrlSearchParamsCtor>(this);
jsObjects[UrlSearchParamsProto] = memoryManager->allocate<UrlSearchParamsPrototype>();
str = newString(QStringLiteral("get [Symbol.species]"));
@@ -703,19 +701,19 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
sequencePrototype()->cast<SequencePrototype>()->init();
- jsObjects[WeakMap_Ctor] = memoryManager->allocate<WeakMapCtor>(global);
+ jsObjects[WeakMap_Ctor] = memoryManager->allocate<WeakMapCtor>(this);
jsObjects[WeakMapProto] = memoryManager->allocate<WeakMapPrototype>();
static_cast<WeakMapPrototype *>(weakMapPrototype())->init(this, weakMapCtor());
- jsObjects[Map_Ctor] = memoryManager->allocate<MapCtor>(global);
+ jsObjects[Map_Ctor] = memoryManager->allocate<MapCtor>(this);
jsObjects[MapProto] = memoryManager->allocate<MapPrototype>();
static_cast<MapPrototype *>(mapPrototype())->init(this, mapCtor());
- jsObjects[WeakSet_Ctor] = memoryManager->allocate<WeakSetCtor>(global);
+ jsObjects[WeakSet_Ctor] = memoryManager->allocate<WeakSetCtor>(this);
jsObjects[WeakSetProto] = memoryManager->allocate<WeakSetPrototype>();
static_cast<WeakSetPrototype *>(weakSetPrototype())->init(this, weakSetCtor());
- jsObjects[Set_Ctor] = memoryManager->allocate<SetCtor>(global);
+ jsObjects[Set_Ctor] = memoryManager->allocate<SetCtor>(this);
jsObjects[SetProto] = memoryManager->allocate<SetPrototype>();
static_cast<SetPrototype *>(setPrototype())->init(this, setCtor());
@@ -723,33 +721,34 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
// promises
//
- jsObjects[Promise_Ctor] = memoryManager->allocate<PromiseCtor>(global);
+ jsObjects[Promise_Ctor] = memoryManager->allocate<PromiseCtor>(this);
jsObjects[PromiseProto] = memoryManager->allocate<PromisePrototype>();
static_cast<PromisePrototype *>(promisePrototype())->init(this, promiseCtor());
// typed arrays
- jsObjects[SharedArrayBuffer_Ctor] = memoryManager->allocate<SharedArrayBufferCtor>(global);
+ jsObjects[SharedArrayBuffer_Ctor] = memoryManager->allocate<SharedArrayBufferCtor>(this);
jsObjects[SharedArrayBufferProto] = memoryManager->allocate<SharedArrayBufferPrototype>();
static_cast<SharedArrayBufferPrototype *>(sharedArrayBufferPrototype())->init(this, sharedArrayBufferCtor());
- jsObjects[ArrayBuffer_Ctor] = memoryManager->allocate<ArrayBufferCtor>(global);
+ jsObjects[ArrayBuffer_Ctor] = memoryManager->allocate<ArrayBufferCtor>(this);
jsObjects[ArrayBufferProto] = memoryManager->allocate<ArrayBufferPrototype>();
static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor());
- jsObjects[DataView_Ctor] = memoryManager->allocate<DataViewCtor>(global);
+ jsObjects[DataView_Ctor] = memoryManager->allocate<DataViewCtor>(this);
jsObjects[DataViewProto] = memoryManager->allocate<DataViewPrototype>();
static_cast<DataViewPrototype *>(dataViewPrototype())->init(this, dataViewCtor());
jsObjects[ValueTypeProto] = (Heap::Base *) nullptr;
jsObjects[SignalHandlerProto] = (Heap::Base *) nullptr;
+ jsObjects[TypeWrapperProto] = (Heap::Base *) nullptr;
- jsObjects[IntrinsicTypedArray_Ctor] = memoryManager->allocate<IntrinsicTypedArrayCtor>(global);
+ jsObjects[IntrinsicTypedArray_Ctor] = memoryManager->allocate<IntrinsicTypedArrayCtor>(this);
jsObjects[IntrinsicTypedArrayProto] = memoryManager->allocate<IntrinsicTypedArrayPrototype>();
static_cast<IntrinsicTypedArrayPrototype *>(intrinsicTypedArrayPrototype())
->init(this, static_cast<IntrinsicTypedArrayCtor *>(intrinsicTypedArrayCtor()));
for (int i = 0; i < NTypedArrayTypes; ++i) {
- static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocate<TypedArrayCtor>(global, Heap::TypedArray::Type(i));
+ static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocate<TypedArrayCtor>(this, Heap::TypedArray::Type(i));
static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->allocate<TypedArrayPrototype>(Heap::TypedArray::Type(i));
typedArrayPrototype[i].as<TypedArrayPrototype>()->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].as<Object>()));
}
@@ -796,14 +795,14 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->allocate<MathObject>()));
globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->allocate<JsonObject>()));
globalObject->defineDefaultProperty(QStringLiteral("Reflect"), (o = memoryManager->allocate<Reflect>()));
- globalObject->defineDefaultProperty(QStringLiteral("Proxy"), (o = memoryManager->allocate<Proxy>(rootContext())));
+ globalObject->defineDefaultProperty(QStringLiteral("Proxy"), (o = memoryManager->allocate<Proxy>(this)));
globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Value::undefinedValue());
globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Value::fromDouble(std::numeric_limits<double>::quiet_NaN()));
globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Value::fromDouble(Q_INFINITY));
- jsObjects[Eval_Function] = memoryManager->allocate<EvalFunction>(global);
+ jsObjects[Eval_Function] = memoryManager->allocate<EvalFunction>(this);
globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction());
// ES6: 20.1.2.12 & 20.1.2.13:
@@ -832,7 +831,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
globalObject->defineDefaultProperty(QStringLiteral("escape"), GlobalFunctions::method_escape, 1);
globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1);
- ScopedFunctionObject t(scope, memoryManager->allocate<FunctionObject>(rootContext(), nullptr, ::throwTypeError));
+ ScopedFunctionObject t(
+ scope,
+ memoryManager->allocate<DynamicFunctionObject>(this, nullptr, ::throwTypeError));
t->defineReadonlyProperty(id_length(), Value::fromInt32(0));
t->setInternalClass(t->internalClass()->cryopreserved());
jsObjects[ThrowerObject] = t;
@@ -2478,18 +2479,22 @@ bool convertToIterable(QMetaType metaType, void *data, Source *sequence)
return false;
const QMetaType elementMetaType = iterable.valueMetaType();
- QVariant element(elementMetaType);
for (qsizetype i = 0, end = sequence->getLength(); i < end; ++i) {
- if (!ExecutionEngine::metaTypeFromJS(sequence->get(i), elementMetaType, element.data()))
- element = QVariant(elementMetaType);
+ QVariant element(elementMetaType);
+ ExecutionEngine::metaTypeFromJS(sequence->get(i), elementMetaType, element.data());
iterable.addValue(element, QSequentialIterable::AtEnd);
}
return true;
}
-// Converts a JS value to a meta-type.
-// data must point to a place that can store a value of the given type.
-// Returns true if conversion succeeded, false otherwise.
+/*!
+ * \internal
+ *
+ * Converts a JS value to a meta-type.
+ * \a data must point to a default-constructed instance of \a metaType.
+ * Returns \c true if conversion succeeded, \c false otherwise. In the latter case,
+ * \a data is not modified.
+ */
bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, void *data)
{
// check if it's one of the types we know
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 8e1bd24f6b..0958ab3ab5 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -217,6 +217,7 @@ public:
MapProto,
IntrinsicTypedArrayProto,
ValueTypeProto,
+ TypeWrapperProto,
SignalHandlerProto,
IteratorProto,
ForInIteratorProto,
@@ -342,6 +343,7 @@ public:
Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); }
Object *signalHandlerPrototype() const { return reinterpret_cast<Object *>(jsObjects + SignalHandlerProto); }
+ Object *typeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeWrapperProto); }
Object *iteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + IteratorProto); }
Object *forInIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ForInIteratorProto); }
Object *setIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetIteratorProto); }
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 35b5952d38..02145a0243 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -182,14 +182,14 @@ DEFINE_OBJECT_VTABLE(SyntaxErrorCtor);
DEFINE_OBJECT_VTABLE(TypeErrorCtor);
DEFINE_OBJECT_VTABLE(URIErrorCtor);
-void Heap::ErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::ErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Error"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Error"));
}
-void Heap::ErrorCtor::init(QV4::ExecutionContext *scope, const QString &name)
+void Heap::ErrorCtor::init(QV4::ExecutionEngine *engine, const QString &name)
{
- Heap::FunctionObject::init(scope, name);
+ Heap::FunctionObject::init(engine, name);
}
ReturnedValue ErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -203,9 +203,9 @@ ReturnedValue ErrorCtor::virtualCall(const FunctionObject *f, const Value *, con
return f->callAsConstructor(argv, argc);
}
-void Heap::EvalErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::EvalErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("EvalError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("EvalError"));
}
ReturnedValue EvalErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -214,9 +214,9 @@ ReturnedValue EvalErrorCtor::virtualCallAsConstructor(const FunctionObject *f, c
return ErrorObject::create<EvalErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::RangeErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::RangeErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("RangeError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("RangeError"));
}
ReturnedValue RangeErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -225,9 +225,9 @@ ReturnedValue RangeErrorCtor::virtualCallAsConstructor(const FunctionObject *f,
return ErrorObject::create<RangeErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::ReferenceErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::ReferenceErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("ReferenceError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("ReferenceError"));
}
ReturnedValue ReferenceErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -236,9 +236,9 @@ ReturnedValue ReferenceErrorCtor::virtualCallAsConstructor(const FunctionObject
return ErrorObject::create<ReferenceErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::SyntaxErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::SyntaxErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("SyntaxError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("SyntaxError"));
}
ReturnedValue SyntaxErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -247,9 +247,9 @@ ReturnedValue SyntaxErrorCtor::virtualCallAsConstructor(const FunctionObject *f,
return ErrorObject::create<SyntaxErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::TypeErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::TypeErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("TypeError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("TypeError"));
}
ReturnedValue TypeErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -258,9 +258,9 @@ ReturnedValue TypeErrorCtor::virtualCallAsConstructor(const FunctionObject *f, c
return ErrorObject::create<TypeErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::URIErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::URIErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("URIError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("URIError"));
}
ReturnedValue URIErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 541f5cae36..f9adbb443b 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -79,32 +79,32 @@ struct URIErrorObject : ErrorObject {
};
struct ErrorCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
- void init(QV4::ExecutionContext *scope, const QString &name);
+ void init(ExecutionEngine *engine);
+ void init(ExecutionEngine *engine, const QString &name);
};
struct EvalErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct RangeErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct ReferenceErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct SyntaxErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct TypeErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct URIErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h
index 3f3335ef4e..930e138732 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit_p.h
+++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h
@@ -134,6 +134,7 @@ public:
bool ignoresFunctionSignature() const { return m_compilationUnit->ignoresFunctionSignature(); }
bool valueTypesAreCopied() const { return m_compilationUnit->valueTypesAreCopied(); }
bool valueTypesAreAddressable() const { return m_compilationUnit->valueTypesAreAddressable(); }
+ bool valueTypesAreAssertable() const { return m_compilationUnit->valueTypesAreAssertable(); }
bool componentsAreBound() const { return m_compilationUnit->componentsAreBound(); }
bool isESModule() const { return m_compilationUnit->isESModule(); }
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index ae36b563e0..82646e2822 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -1,20 +1,18 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qml/qqmlprivate.h"
#include "qv4function_p.h"
-#include "qv4managed_p.h"
-#include "qv4string_p.h"
-#include "qv4value_p.h"
-#include "qv4engine_p.h"
-#include <private/qv4mm_p.h>
-#include <private/qv4identifiertable_p.h>
+
+#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qqmltype_p_p.h>
+
+#include <private/qv4engine_p.h>
#include <private/qv4functiontable_p.h>
-#include <assembler/MacroAssemblerCodeRef.h>
-#include <private/qv4vme_moth_p.h>
-#include <private/qqmlglobal_p.h>
+#include <private/qv4identifiertable_p.h>
#include <private/qv4jscall_p.h>
-#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qv4vme_moth_p.h>
+
+#include <assembler/MacroAssemblerCodeRef.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index ab6a34435f..e9f91fbc06 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -30,84 +30,57 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(FunctionObject);
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name,
- VTable::Call call, VTable::CallWithMetaTypes callWithMetaTypes)
+void Heap::FunctionObject::init(QV4::ExecutionEngine *engine, QV4::String *name)
{
- jsCall = call;
- jsCallWithMetaTypes = callWithMetaTypes;
- jsConstruct = nullptr;
-
Object::init();
- this->scope.set(scope->engine(), scope->d());
- Scope s(scope->engine());
+ Scope s(engine);
ScopedFunctionObject f(s, this);
if (name)
f->setName(name);
}
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name)
+void Heap::FunctionObject::init(QV4::ExecutionEngine *engine, const QString &name)
{
- ExecutionEngine *e = scope->engine();
-
- jsCall = vtable()->call;
- jsCallWithMetaTypes = vtable()->callWithMetaTypes;
- jsConstruct = vtable()->callAsConstructor;
-
- Object::init();
- this->scope.set(scope->engine(), scope->d());
- Scope s(e);
- ScopedFunctionObject f(s, this);
- if (name)
- f->setName(name);
+ Scope valueScope(engine);
+ ScopedString s(valueScope, engine->newString(name));
+ init(engine, s);
}
-
-
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n)
-{
- jsCall = vtable()->call;
- jsCallWithMetaTypes = vtable()->callWithMetaTypes;
- jsConstruct = vtable()->callAsConstructor;
-
- Object::init();
- setFunction(function);
- this->scope.set(scope->engine(), scope->d());
- Scope s(scope->engine());
- ScopedString name(s, n ? n->d() : function->name());
- ScopedFunctionObject f(s, this);
- if (name)
- f->setName(name);
-}
-
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const QString &name)
+void Heap::FunctionObject::init()
{
- Scope valueScope(scope);
- ScopedString s(valueScope, valueScope.engine->newString(name));
- init(scope, s);
+ init(internalClass->engine, static_cast<QV4::String *>(nullptr));
}
-void Heap::FunctionObject::init()
+void Heap::JavaScriptFunctionObject::init(
+ QV4::ExecutionContext *scope, Function *function, QV4::String *n)
{
- jsCall = vtable()->call;
- jsCallWithMetaTypes = vtable()->callWithMetaTypes;
- jsConstruct = vtable()->callAsConstructor;
-
- Object::init();
- this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d());
+ Q_ASSERT(n || function);
+ Scope s(scope->engine());
+ ScopedString name(s, n ? n->d() : function->name());
+ FunctionObject::init(s.engine, name);
+ this->scope.set(s.engine, scope->d());
+ setFunction(function);
}
-void Heap::FunctionObject::setFunction(Function *f)
+void Heap::JavaScriptFunctionObject::setFunction(Function *f)
{
if (f) {
function = f;
function->executableCompilationUnit()->addref();
}
}
-void Heap::FunctionObject::destroy()
+void Heap::JavaScriptFunctionObject::destroy()
{
if (function)
function->executableCompilationUnit()->release();
- Object::destroy();
+ FunctionObject::destroy();
+}
+
+void Heap::DynamicFunctionObject::init(
+ QV4::ExecutionEngine *engine, QV4::String *name, VTable::Call call)
+{
+ FunctionObject::init(engine, name);
+ jsCall = call;
}
void FunctionObject::createDefaultPrototypeProperty(uint protoConstructorSlot)
@@ -121,32 +94,29 @@ void FunctionObject::createDefaultPrototypeProperty(uint protoConstructorSlot)
defineDefaultProperty(s.engine->id_prototype(), proto, Attr_NotEnumerable|Attr_NotConfigurable);
}
-void FunctionObject::call(QObject *thisObject, void **a, const QMetaType *types, int argc)
+ReturnedValue FunctionObject::name() const
{
- if (const auto callWithMetaTypes = d()->jsCallWithMetaTypes) {
- callWithMetaTypes(this, thisObject, a, types, argc);
- return;
- }
-
- QV4::convertAndCall(engine(), thisObject, a, types, argc,
- [this](const Value *thisObject, const Value *argv, int argc) {
- return call(thisObject, argv, argc);
- });
+ return get(engine()->id_name());
}
-ReturnedValue FunctionObject::name() const
+ReturnedValue FunctionObject::failCall() const
{
- return get(scope()->internalClass->engine->id_name());
+ return engine()->throwTypeError(QStringLiteral("Function can only be called with |new|."));
}
-ReturnedValue FunctionObject::virtualCall(const FunctionObject *, const Value *, const Value *, int)
+ReturnedValue FunctionObject::failCallAsConstructor() const
{
- return Encode::undefined();
+ return engine()->throwTypeError(QStringLiteral("Function is not a constructor."));
}
-void FunctionObject::virtualCallWithMetaTypes(
- const FunctionObject *, QObject *, void **, const QMetaType *, int)
+void FunctionObject::virtualConvertAndCall(
+ const FunctionObject *f, QObject *thisObject,
+ void **argv, const QMetaType *types, int argc)
{
+ QV4::convertAndCall(f->engine(), thisObject, argv, types, argc,
+ [f](const Value *thisObject, const Value *argv, int argc) {
+ return f->call(thisObject, argv, argc);
+ });
}
Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function)
@@ -156,15 +126,20 @@ Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *sco
return scope->engine()->memoryManager->allocate<ScriptFunction>(scope, function);
}
-Heap::FunctionObject *FunctionObject::createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor)
+Heap::FunctionObject *FunctionObject::createConstructorFunction(
+ ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor)
{
+ QV4::ExecutionEngine *engine = scope->engine();
if (!function) {
- Heap::DefaultClassConstructorFunction *c = scope->engine()->memoryManager->allocate<DefaultClassConstructorFunction>(scope);
+ Heap::DefaultClassConstructorFunction *c
+ = engine->memoryManager->allocate<DefaultClassConstructorFunction>(scope);
c->isDerivedConstructor = isDerivedConstructor;
return c;
}
- Heap::ConstructorFunction *c = scope->engine()->memoryManager->allocate<ConstructorFunction>(scope, function);
- c->homeObject.set(scope->engine(), homeObject->d());
+
+ Heap::ConstructorFunction *c
+ = engine->memoryManager->allocate<ConstructorFunction>(scope, function);
+ c->homeObject.set(engine, homeObject->d());
c->isDerivedConstructor = isDerivedConstructor;
return c;
}
@@ -183,7 +158,8 @@ Heap::FunctionObject *FunctionObject::createBuiltinFunction(ExecutionEngine *eng
if (!name)
name = engine->newString(QChar::fromLatin1('[') + QStringView{nameOrSymbol->toQString()}.mid(1) + QChar::fromLatin1(']'));
- ScopedFunctionObject function(scope, engine->memoryManager->allocate<FunctionObject>(engine->rootContext(), name, code));
+ ScopedFunctionObject function(
+ scope, engine->memoryManager->allocate<DynamicFunctionObject>(engine, name, code));
function->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(argumentCount));
return function->d();
}
@@ -199,16 +175,29 @@ ReturnedValue FunctionObject::getHomeObject() const
return Encode::undefined();
}
-QQmlSourceLocation FunctionObject::sourceLocation() const
+DEFINE_OBJECT_VTABLE(JavaScriptFunctionObject);
+
+QQmlSourceLocation JavaScriptFunctionObject::sourceLocation() const
{
return d()->function->sourceLocation();
}
+DEFINE_OBJECT_VTABLE(DynamicFunctionObject);
+
+ReturnedValue DynamicFunctionObject::virtualCall(
+ const FunctionObject *f, const Value *thisObject, const Value *argv, int argc) {
+ Heap::DynamicFunctionObject *d = static_cast<const DynamicFunctionObject *>(f)->d();
+ if (d->jsCall)
+ return d->jsCall(f, thisObject, argv, argc);
+ return d->internalClass->engine->throwTypeError(
+ QStringLiteral("Function can only be called with |new|."));
+}
+
DEFINE_OBJECT_VTABLE(FunctionCtor);
-void Heap::FunctionCtor::init(QV4::ExecutionContext *scope)
+void Heap::FunctionCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Function"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Function"));
}
// 15.3.2
@@ -311,6 +300,12 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(engine->symbol_hasInstance(), method_hasInstance, 1, Attr_ReadOnly);
}
+ReturnedValue FunctionPrototype::virtualCall(
+ const FunctionObject *, const Value *, const Value *, int)
+{
+ return Encode::undefined();
+}
+
ReturnedValue FunctionPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
ExecutionEngine *v4 = b->engine();
@@ -427,10 +422,13 @@ ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Valu
boundArgs->set(scope.engine, i, argv[i + 1]);
}
- ScopedContext ctx(scope, target->scope());
- Scoped<BoundFunction> bound(scope, BoundFunction::create(ctx, target, boundThis, boundArgs));
- bound->d()->setFunction(target->function());
- return bound->asReturnedValue();
+ if (target->isConstructor()) {
+ return scope.engine->memoryManager->allocate<BoundConstructor>(target, boundThis, boundArgs)
+ ->asReturnedValue();
+ }
+
+ return scope.engine->memoryManager->allocate<BoundFunction>(target, boundThis, boundArgs)
+ ->asReturnedValue();
}
ReturnedValue FunctionPrototype::method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
@@ -490,7 +488,9 @@ DEFINE_OBJECT_VTABLE(ArrowFunction);
void ArrowFunction::virtualCallWithMetaTypes(const FunctionObject *fo, QObject *thisObject,
void **a, const QMetaType *types, int argc)
{
- if (fo->function()->kind != Function::AotCompiled) {
+ const ArrowFunction *self = static_cast<const ArrowFunction *>(fo);
+ Function *function = self->function();
+ if (function->kind != Function::AotCompiled) {
QV4::convertAndCall(fo->engine(), thisObject, a, types, argc,
[fo](const Value *thisObject, const Value *argv, int argc) {
return ArrowFunction::virtualCall(fo, thisObject, argv, argc);
@@ -499,16 +499,17 @@ void ArrowFunction::virtualCallWithMetaTypes(const FunctionObject *fo, QObject *
}
QV4::Scope scope(fo->engine());
- QV4::Scoped<ExecutionContext> context(scope, fo->scope());
+ QV4::Scoped<ExecutionContext> context(scope, self->scope());
MetaTypesStackFrame frame;
- frame.init(fo->function(), thisObject, context, a, types, argc);
+ frame.init(function, thisObject, context, a, types, argc);
frame.push(scope.engine);
Moth::VME::exec(&frame, scope.engine);
frame.pop(scope.engine);
}
-static ReturnedValue qfoDoCall(const QV4::FunctionObject *fo, const QV4::Value *thisObject,
- const QV4::Value *argv, int argc)
+static ReturnedValue qfoDoCall(
+ const QV4::JavaScriptFunctionObject *fo, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc)
{
ExecutionEngine *engine = fo->engine();
JSTypesStackFrame frame;
@@ -535,7 +536,8 @@ static ReturnedValue qfoDoCall(const QV4::FunctionObject *fo, const QV4::Value *
ReturnedValue ArrowFunction::virtualCall(const QV4::FunctionObject *fo, const Value *thisObject,
const QV4::Value *argv, int argc)
{
- Function *function = fo->function();
+ const ArrowFunction *self = static_cast<const ArrowFunction *>(fo);
+ Function *function = self->function();
switch (function->kind) {
case Function::AotCompiled:
return QV4::convertAndCall(
@@ -546,34 +548,24 @@ ReturnedValue ArrowFunction::virtualCall(const QV4::FunctionObject *fo, const Va
case Function::JsTyped:
return QV4::coerceAndCall(
fo->engine(), &function->jsTypedFunction, function->compiledFunction, argv, argc,
- [fo, thisObject](const Value *argv, int argc) {
- return qfoDoCall(fo, thisObject, argv, argc);
+ [self, thisObject](const Value *argv, int argc) {
+ return qfoDoCall(self, thisObject, argv, argc);
});
default:
break;
}
- return qfoDoCall(fo, thisObject, argv, argc);
+ return qfoDoCall(self, thisObject, argv, argc);
}
void Heap::ArrowFunction::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n)
{
- FunctionObject::init();
- this->scope.set(scope->engine(), scope->d());
-
- setFunction(function);
Q_ASSERT(function);
+ JavaScriptFunctionObject::init(scope, function, n);
Scope s(scope);
- ScopedFunctionObject f(s, this);
-
- ScopedString name(s, n ? n->d() : function->name());
- if (name)
- f->setName(name);
-
Q_ASSERT(internalClass && internalClass->verifyIndex(s.engine->id_length()->propertyKey(), Index_Length));
setProperty(s.engine, Index_Length, Value::fromInt32(int(function->compiledFunction->length)));
- canBeTailCalled = true;
}
void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function)
@@ -586,6 +578,13 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function
f->createDefaultPrototypeProperty(Heap::FunctionObject::Index_ProtoConstructor);
}
+void Heap::DefaultClassConstructorFunction::init(QV4::ExecutionContext *scope)
+{
+ Scope s(scope->engine());
+ FunctionObject::init(s.engine, nullptr);
+ this->scope.set(s.engine, scope->d());
+}
+
Heap::InternalClass *ScriptFunction::classForConstructor() const
{
Scope scope(engine());
@@ -613,8 +612,8 @@ ReturnedValue ConstructorFunction::virtualCallAsConstructor(const FunctionObject
ExecutionEngine *v4 = f->engine();
JSTypesStackFrame frame;
- frame.init(f->function(), argv, argc);
- frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
+ frame.init(c->function(), argv, argc);
+ frame.setupJSFrame(v4->jsStackTop, *f, c->scope(),
Value::emptyValue(),
newTarget ? *newTarget : Value::undefinedValue());
@@ -668,7 +667,7 @@ ReturnedValue DefaultClassConstructorFunction::virtualCallAsConstructor(const Fu
JSTypesStackFrame frame;
frame.init(nullptr, argv, argc);
- frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
+ frame.setupJSFrame(v4->jsStackTop, *f, c->scope(),
Value::undefinedValue(),
newTarget ? *newTarget : Value::undefinedValue(), argc, argc);
@@ -705,33 +704,39 @@ DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
DEFINE_OBJECT_VTABLE(BoundFunction);
-void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject *target,
- const Value &boundThis, QV4::MemberData *boundArgs)
+void Heap::BoundFunction::init(
+ QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs)
{
- Scope s(scope);
- Heap::FunctionObject::init(scope, QStringLiteral("__bound function__"));
+ ExecutionEngine *engine = target->engine();
+ Scope s(engine);
+ ScopedString name(s, engine->newString(QStringLiteral("__bound function__")));
+ if (auto *js = target->as<QV4::JavaScriptFunctionObject>()) {
+ ScopedContext ctx(s, js->scope());
+ JavaScriptFunctionObject::init(ctx, js->function(), name);
+ } else {
+ Q_ASSERT(name);
+ JavaScriptFunctionObject::init(engine->rootContext(), nullptr, name);
+ }
+
this->target.set(s.engine, target->d());
this->boundArgs.set(s.engine, boundArgs ? boundArgs->d() : nullptr);
- this->boundThis.set(scope->engine(), boundThis);
-
- if (!target->isConstructor())
- jsConstruct = nullptr;
+ this->boundThis.set(s.engine, boundThis);
ScopedObject f(s, this);
- ScopedValue l(s, target->get(s.engine->id_length()));
+ ScopedValue l(s, target->get(engine->id_length()));
int len = l->toUInt32();
if (boundArgs)
len -= boundArgs->size();
if (len < 0)
len = 0;
- f->defineReadonlyConfigurableProperty(s.engine->id_length(), Value::fromInt32(len));
+ f->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(len));
ScopedProperty pd(s);
- pd->value = s.engine->thrower();
- pd->set = s.engine->thrower();
- f->insertMember(s.engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
- f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ pd->value = engine->thrower();
+ pd->set = engine->thrower();
+ f->insertMember(engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ f->insertMember(engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
}
ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *, const Value *argv, int argc)
@@ -755,7 +760,10 @@ ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *
return checkedResult(v4, target->call(jsCallData));
}
-ReturnedValue BoundFunction::virtualCallAsConstructor(const FunctionObject *fo, const Value *argv, int argc, const Value *)
+DEFINE_OBJECT_VTABLE(BoundConstructor);
+
+ReturnedValue BoundConstructor::virtualCallAsConstructor(
+ const FunctionObject *fo, const Value *argv, int argc, const Value *)
{
const BoundFunction *f = static_cast<const BoundFunction *>(fo);
Scope scope(f->engine());
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 573848f62a..f4a2935b5a 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -28,36 +28,41 @@ namespace QV4 {
struct IndexedBuiltinFunction;
struct JSCallData;
-namespace Heap {
-
+// A FunctionObject is generally something that can be called, either with a JavaScript
+// signature (QV4::Value etc) or with a C++ signature (QMetaType etc). For this, it has
+// the Call and CallWithMetaTypes VTable entries.
+// Some FunctionObjects need to select the actual implementation of the call at run time.
+// This comese in two flavors:
+// 1. The implementation is a JavaScript function. For these we have
+// JavaScriptFunctionObject that holds a QV4::Function member to defer the call to.
+// 2. The implementation is a C++ function. For these we have DynamicFunctionObject that
+// holds another Call member in the heap object to defer the call to.
+// In addition, a FunctionObject may want to be called as constructor. For this we have
+// another VTable entry and a flag in the heap object.
-#define FunctionObjectMembers(class, Member) \
- Member(class, Pointer, ExecutionContext *, scope) \
- Member(class, NoMark, Function *, function) \
- Member(class, NoMark, VTable::Call, jsCall) \
- Member(class, NoMark, VTable::CallAsConstructor, jsConstruct) \
- Member(class, NoMark, VTable::CallWithMetaTypes, jsCallWithMetaTypes) \
- Member(class, NoMark, bool, canBeTailCalled)
+namespace Heap {
+#define FunctionObjectMembers(class, Member)
DECLARE_HEAP_OBJECT(FunctionObject, Object) {
- DECLARE_MARKOBJECTS(FunctionObject)
enum {
Index_ProtoConstructor = 0,
Index_Prototype = 0,
Index_HasInstance = 1,
};
- bool isConstructor() const {
- return jsConstruct != nullptr;
- }
-
- Q_QML_EXPORT void init(
- QV4::ExecutionContext *scope, QV4::String *name,
- VTable::Call call, VTable::CallWithMetaTypes callWithMetaTypes = nullptr);
- Q_QML_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr);
- Q_QML_EXPORT void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
- Q_QML_EXPORT void init(QV4::ExecutionContext *scope, const QString &name);
+ Q_QML_EXPORT void init(QV4::ExecutionEngine *engine, QV4::String *name = nullptr);
+ Q_QML_EXPORT void init(QV4::ExecutionEngine *engine, const QString &name);
Q_QML_EXPORT void init();
+};
+
+#define JavaScriptFunctionObjectMembers(class, Member) \
+ Member(class, Pointer, ExecutionContext *, scope) \
+ Member(class, NoMark, Function *, function)
+
+DECLARE_HEAP_OBJECT(JavaScriptFunctionObject, FunctionObject) {
+ DECLARE_MARKOBJECTS(JavaScriptFunctionObject)
+
+ void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
Q_QML_EXPORT void destroy();
void setFunction(Function *f);
@@ -66,8 +71,18 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) {
unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; }
};
+#define DynamicFunctionObjectMembers(class, Member) \
+ Member(class, NoMark, VTable::Call, jsCall)
+
+DECLARE_HEAP_OBJECT(DynamicFunctionObject, FunctionObject) {
+ // NB: We might add a CallWithMetaTypes member to this struct and implement our
+ // builtins with metatypes, to be called from C++ code. This would make them
+ // available to qmlcachegen's C++ code generation.
+ void init(ExecutionEngine *engine, QV4::String *name, VTable::Call call);
+};
+
struct FunctionCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
struct FunctionPrototype : FunctionObject {
@@ -76,12 +91,12 @@ struct FunctionPrototype : FunctionObject {
// A function object with an additional index into a list.
// Used by Models to refer to property roles.
-struct IndexedBuiltinFunction : FunctionObject {
- inline void init(QV4::ExecutionContext *scope, qsizetype index, VTable::Call call);
+struct IndexedBuiltinFunction : DynamicFunctionObject {
+ inline void init(QV4::ExecutionEngine *engine, qsizetype index, VTable::Call call);
qsizetype index;
};
-struct ArrowFunction : FunctionObject {
+struct ArrowFunction : JavaScriptFunctionObject {
enum {
Index_Name = Index_HasInstance + 1,
Index_Length
@@ -116,9 +131,15 @@ DECLARE_HEAP_OBJECT(ConstructorFunction, ScriptFunction) {
bool isDerivedConstructor;
};
-struct DefaultClassConstructorFunction : FunctionObject
-{
+#define DefaultClassConstructorFunctionMembers(class, Member) \
+ Member(class, Pointer, ExecutionContext *, scope)
+
+DECLARE_HEAP_OBJECT(DefaultClassConstructorFunction, FunctionObject) {
+ DECLARE_MARKOBJECTS(DefaultClassConstructorFunction)
+
bool isDerivedConstructor;
+
+ void init(QV4::ExecutionContext *scope);
};
#define BoundFunctionMembers(class, Member) \
@@ -126,66 +147,72 @@ struct DefaultClassConstructorFunction : FunctionObject
Member(class, HeapValue, HeapValue, boundThis) \
Member(class, Pointer, MemberData *, boundArgs)
-DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) {
+DECLARE_HEAP_OBJECT(BoundFunction, JavaScriptFunctionObject) {
DECLARE_MARKOBJECTS(BoundFunction)
- void init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs);
+ void init(QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs);
};
+struct BoundConstructor : BoundFunction {};
+
}
struct Q_QML_EXPORT FunctionObject: Object {
- enum {
- IsFunctionObject = true
- };
V4_OBJECT2(FunctionObject, Object)
Q_MANAGED_TYPE(FunctionObject)
V4_INTERNALCLASS(FunctionObject)
V4_PROTOTYPE(functionPrototype)
- V4_NEEDS_DESTROY
enum { NInlineProperties = 1 };
- bool canBeTailCalled() const { return d()->canBeTailCalled; }
- Heap::ExecutionContext *scope() const { return d()->scope; }
- Function *function() const { return d()->function; }
+ bool canBeTailCalled() const { return vtable()->isTailCallable; }
ReturnedValue name() const;
- unsigned int formalParameterCount() const { return d()->formalParameterCount(); }
- unsigned int varCount() const { return d()->varCount(); }
void setName(String *name) {
defineReadonlyConfigurableProperty(engine()->id_name(), *name);
}
void createDefaultPrototypeProperty(uint protoConstructorSlot);
- inline ReturnedValue callAsConstructor(const JSCallData &data) const;
- ReturnedValue callAsConstructor(const Value *argv, int argc, const Value *newTarget = nullptr) const {
- if (!d()->jsConstruct)
- return engine()->throwTypeError(QStringLiteral("Function is not a constructor."));
- return d()->jsConstruct(this, argv, argc, newTarget ? newTarget : this);
+ ReturnedValue callAsConstructor(
+ const Value *argv, int argc, const Value *newTarget = nullptr) const
+ {
+ if (const auto callAsConstructor = vtable()->callAsConstructor)
+ return callAsConstructor(this, argv, argc, newTarget ? newTarget : this);
+ return failCallAsConstructor();
}
- inline ReturnedValue call(const JSCallData &data) const;
- ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const {
- if (!d()->jsCall)
- return engine()->throwTypeError(QStringLiteral("Function can only be called with |new|."));
- return d()->jsCall(this, thisObject, argv, argc);
+
+ ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const
+ {
+ if (const auto call = vtable()->call)
+ return call(this, thisObject, argv, argc);
+ return failCall();
}
- static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
- void call(QObject *thisObject, void **a, const QMetaType *types, int argc);
- static void virtualCallWithMetaTypes(const FunctionObject *f, QObject *thisObject,
- void **a, const QMetaType *types, int argc);
+
+ void call(QObject *thisObject, void **argv, const QMetaType *types, int argc) const
+ {
+ if (const auto callWithMetaTypes = vtable()->callWithMetaTypes)
+ callWithMetaTypes(this, thisObject, argv, types, argc);
+ else
+ failCall();
+ }
+
+ inline ReturnedValue callAsConstructor(const JSCallData &data) const;
+ inline ReturnedValue call(const JSCallData &data) const;
+
+ ReturnedValue failCall() const;
+ ReturnedValue failCallAsConstructor() const;
+ static void virtualConvertAndCall(
+ const FunctionObject *f, QObject *thisObject,
+ void **argv, const QMetaType *types, int argc);
static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function);
static Heap::FunctionObject *createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor);
static Heap::FunctionObject *createMemberFunction(ExecutionContext *scope, Function *function, Object *homeObject, String *name);
static Heap::FunctionObject *createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, VTable::Call code, int argumentCount);
- bool strictMode() const { return d()->function ? d()->function->isStrict() : false; }
bool isBinding() const;
bool isBoundFunction() const;
- bool isConstructor() const {
- return d()->isConstructor();
- }
+ bool isConstructor() const { return vtable()->callAsConstructor; }
ReturnedValue getHomeObject() const;
@@ -195,15 +222,40 @@ struct Q_QML_EXPORT FunctionObject: Object {
bool hasHasInstanceProperty() const {
return !internalClass()->propertyData.at(Heap::FunctionObject::Index_HasInstance).isEmpty();
}
-
- QQmlSourceLocation sourceLocation() const;
};
template<>
inline const FunctionObject *Value::as() const {
- return isManaged() && m()->internalClass->vtable->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : nullptr;
+ if (!isManaged())
+ return nullptr;
+
+ const VTable *vtable = m()->internalClass->vtable;
+ return (vtable->call || vtable->callAsConstructor)
+ ? reinterpret_cast<const FunctionObject *>(this)
+ : nullptr;
}
+struct Q_QML_EXPORT JavaScriptFunctionObject: FunctionObject
+{
+ V4_OBJECT2(JavaScriptFunctionObject, FunctionObject)
+ V4_NEEDS_DESTROY
+
+ Heap::ExecutionContext *scope() const { return d()->scope; }
+
+ Function *function() const { return d()->function; }
+ unsigned int formalParameterCount() const { return d()->formalParameterCount(); }
+ unsigned int varCount() const { return d()->varCount(); }
+ bool strictMode() const { return d()->function ? d()->function->isStrict() : false; }
+ QQmlSourceLocation sourceLocation() const;
+};
+
+struct Q_QML_EXPORT DynamicFunctionObject: FunctionObject
+{
+ V4_OBJECT2(DynamicFunctionObject, FunctionObject)
+
+ static ReturnedValue virtualCall(
+ const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
struct FunctionCtor: FunctionObject
{
@@ -225,6 +277,9 @@ struct FunctionPrototype: FunctionObject
void init(ExecutionEngine *engine, Object *ctor);
+ static ReturnedValue virtualCall(
+ const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+
static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_apply(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
@@ -232,23 +287,26 @@ struct FunctionPrototype: FunctionObject
static ReturnedValue method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
-struct Q_QML_EXPORT IndexedBuiltinFunction : FunctionObject
+struct Q_QML_EXPORT IndexedBuiltinFunction : DynamicFunctionObject
{
- V4_OBJECT2(IndexedBuiltinFunction, FunctionObject)
+ V4_OBJECT2(IndexedBuiltinFunction, DynamicFunctionObject)
};
void Heap::IndexedBuiltinFunction::init(
- QV4::ExecutionContext *scope, qsizetype index, VTable::Call call)
+ QV4::ExecutionEngine *engine, qsizetype index, VTable::Call call)
{
- Heap::FunctionObject::init(scope);
+ Heap::FunctionObject::init(engine);
this->jsCall = call;
this->index = index;
}
-struct ArrowFunction : FunctionObject {
- V4_OBJECT2(ArrowFunction, FunctionObject)
+struct ArrowFunction : JavaScriptFunctionObject {
+ V4_OBJECT2(ArrowFunction, JavaScriptFunctionObject)
V4_INTERNALCLASS(ArrowFunction)
- enum { NInlineProperties = 3 };
+ enum {
+ NInlineProperties = 3,
+ IsTailCallable = true,
+ };
static void virtualCallWithMetaTypes(const FunctionObject *f, QObject *thisObject,
void **a, const QMetaType *types, int argc);
@@ -279,29 +337,33 @@ struct ConstructorFunction : ScriptFunction {
struct DefaultClassConstructorFunction : FunctionObject {
V4_OBJECT2(DefaultClassConstructorFunction, FunctionObject)
+
+ Heap::ExecutionContext *scope() const { return d()->scope; }
static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
-struct BoundFunction: FunctionObject {
- V4_OBJECT2(BoundFunction, FunctionObject)
-
- static Heap::BoundFunction *create(ExecutionContext *scope, FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs)
- {
- return scope->engine()->memoryManager->allocate<BoundFunction>(scope, target, boundThis, boundArgs);
- }
+struct BoundFunction: JavaScriptFunctionObject {
+ V4_OBJECT2(BoundFunction, JavaScriptFunctionObject)
Heap::FunctionObject *target() const { return d()->target; }
Value boundThis() const { return d()->boundThis; }
Heap::MemberData *boundArgs() const { return d()->boundArgs; }
- static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
+struct BoundConstructor: BoundFunction {
+ V4_OBJECT2(BoundConstructor, BoundFunction)
+
+ static ReturnedValue virtualCallAsConstructor(
+ const FunctionObject *f, const Value *argv, int argc, const Value *);
+};
+
inline bool FunctionObject::isBoundFunction() const
{
- return d()->vtable() == BoundFunction::staticVTable();
+ const VTable *vtable = d()->vtable();
+ return vtable == BoundFunction::staticVTable() || vtable == BoundConstructor::staticVTable();
}
inline ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result)
diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp
index e7a63ba185..f2d7dffde5 100644
--- a/src/qml/jsruntime/qv4generatorobject.cpp
+++ b/src/qml/jsruntime/qv4generatorobject.cpp
@@ -13,9 +13,9 @@ DEFINE_OBJECT_VTABLE(GeneratorFunctionCtor);
DEFINE_OBJECT_VTABLE(GeneratorFunction);
DEFINE_OBJECT_VTABLE(GeneratorObject);
-void Heap::GeneratorFunctionCtor::init(QV4::ExecutionContext *scope)
+void Heap::GeneratorFunctionCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("GeneratorFunction"));
+ Heap::FunctionObject::init(engine, QStringLiteral("GeneratorFunction"));
}
ReturnedValue GeneratorFunctionCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4generatorobject_p.h b/src/qml/jsruntime/qv4generatorobject_p.h
index 55ccc133aa..cb2c1962c5 100644
--- a/src/qml/jsruntime/qv4generatorobject_p.h
+++ b/src/qml/jsruntime/qv4generatorobject_p.h
@@ -33,7 +33,7 @@ enum class GeneratorState {
namespace Heap {
struct GeneratorFunctionCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct GeneratorFunction : ArrowFunction {
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index d15fb356c4..e3fc0ac1b3 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -80,6 +80,7 @@ namespace Heap {
struct ArrayObject;
struct DateObject;
struct FunctionObject;
+ struct JavaScriptFunctionObject;
struct ErrorObject;
struct ArgumentsObject;
struct QObjectWrapper;
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 37548ffc9f..989de0de23 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -290,10 +290,10 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok)
DEFINE_OBJECT_VTABLE(EvalFunction);
-void Heap::EvalFunction::init(QV4::ExecutionContext *scope)
+void Heap::EvalFunction::init(QV4::ExecutionEngine *engine)
{
- Scope s(scope);
- Heap::FunctionObject::init(scope, s.engine->id_eval());
+ Scope s(engine);
+ Heap::FunctionObject::init(engine, s.engine->id_eval());
ScopedFunctionObject f(s, this);
f->defineReadonlyConfigurableProperty(s.engine->id_length(), Value::fromInt32(1));
}
diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h
index 71e06ef417..fd23d71332 100644
--- a/src/qml/jsruntime/qv4globalobject_p.h
+++ b/src/qml/jsruntime/qv4globalobject_p.h
@@ -24,7 +24,7 @@ namespace QV4 {
namespace Heap {
struct EvalFunction : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h
index ed1ca983ad..43776e4b62 100644
--- a/src/qml/jsruntime/qv4jscall_p.h
+++ b/src/qml/jsruntime/qv4jscall_p.h
@@ -14,20 +14,17 @@
// We mean it.
//
-#include <private/qqmlengine_p.h>
#include <private/qqmllistwrapper_p.h>
-#include <private/qqmlvaluetype_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
+
#include <private/qv4alloca_p.h>
-#include <private/qv4context_p.h>
#include <private/qv4dateobject_p.h>
#include <private/qv4function_p.h>
#include <private/qv4functionobject_p.h>
-#include <private/qv4object_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4regexpobject_p.h>
#include <private/qv4scopedvalue_p.h>
-#include <private/qv4stackframe_p.h>
+#include <private/qv4sequenceobject_p.h>
#include <private/qv4urlobject_p.h>
#include <private/qv4variantobject_p.h>
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index c5f5fbff8e..aeac8c4914 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -77,7 +77,7 @@ struct Q_QML_EXPORT Managed : Value, VTableBase
IsString = false,
IsStringOrSymbol = false,
IsObject = false,
- IsFunctionObject = false,
+ IsTailCallable = false,
IsErrorObject = false,
IsArrayData = false
};
diff --git a/src/qml/jsruntime/qv4mapobject.cpp b/src/qml/jsruntime/qv4mapobject.cpp
index 4bb9617b93..94cac02556 100644
--- a/src/qml/jsruntime/qv4mapobject.cpp
+++ b/src/qml/jsruntime/qv4mapobject.cpp
@@ -12,14 +12,14 @@ DEFINE_OBJECT_VTABLE(WeakMapCtor);
DEFINE_OBJECT_VTABLE(MapCtor);
DEFINE_OBJECT_VTABLE(MapObject);
-void Heap::WeakMapCtor::init(QV4::ExecutionContext *scope)
+void Heap::WeakMapCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("WeakMap"));
+ Heap::FunctionObject::init(engine, QStringLiteral("WeakMap"));
}
-void Heap::MapCtor::init(QV4::ExecutionContext *scope)
+void Heap::MapCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Map"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Map"));
}
ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget, bool weakMap)
@@ -214,6 +214,16 @@ ReturnedValue WeakMapPrototype::method_set(const FunctionObject *b, const Value
(!argc || !argv[0].isObject()))
return scope.engine->throwTypeError();
+ QV4::WriteBarrier::markCustom(scope.engine, [&](QV4::MarkStack *ms) {
+ if (scope.engine->memoryManager->gcStateMachine->state <= GCState::FreeWeakMaps)
+ return;
+ argv[0].heapObject()->mark(ms);
+ if (argc > 1) {
+ if (auto *h = argv[1].heapObject())
+ h->mark(ms);
+ }
+ });
+
that->d()->esTable->set(argv[0], argc > 1 ? argv[1] : Value::undefinedValue());
return that.asReturnedValue();
}
@@ -317,6 +327,14 @@ ReturnedValue MapPrototype::method_set(const FunctionObject *b, const Value *thi
if (!that || that->d()->isWeakMap)
return scope.engine->throwTypeError();
+ QV4::WriteBarrier::markCustom(scope.engine, [&](QV4::MarkStack *ms) {
+ argv[0].heapObject()->mark(ms);
+ if (argc > 1) {
+ if (auto *h = argv[1].heapObject())
+ h->mark(ms);
+ }
+ });
+
that->d()->esTable->set(argc ? argv[0] : Value::undefinedValue(), argc > 1 ? argv[1] : Value::undefinedValue());
return that.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4mapobject_p.h b/src/qml/jsruntime/qv4mapobject_p.h
index 68bc7ceed8..e7ff02c13a 100644
--- a/src/qml/jsruntime/qv4mapobject_p.h
+++ b/src/qml/jsruntime/qv4mapobject_p.h
@@ -27,11 +27,11 @@ class ESTable;
namespace Heap {
struct WeakMapCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct MapCtor : WeakMapCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct MapObject : Object {
@@ -78,7 +78,7 @@ struct WeakMapPrototype : Object
static ReturnedValue method_delete(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_has(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ Q_AUTOTEST_EXPORT static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
struct MapPrototype : WeakMapPrototype
@@ -92,7 +92,7 @@ struct MapPrototype : WeakMapPrototype
static ReturnedValue method_get(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_has(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_keys(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ Q_AUTOTEST_EXPORT static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get_size(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_values(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index d744e569f5..5299a2568a 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -36,9 +36,9 @@ const NumberLocale *NumberLocale::instance()
return numberLocaleHolder();
}
-void Heap::NumberCtor::init(QV4::ExecutionContext *scope)
+void Heap::NumberCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Number"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Number"));
}
ReturnedValue NumberCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index 8ac2bd1f79..3f0d6d9425 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -25,7 +25,7 @@ namespace QV4 {
namespace Heap {
struct NumberCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index e7f96a12ba..2a78bb4540 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -19,9 +19,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ObjectCtor);
-void Heap::ObjectCtor::init(QV4::ExecutionContext *scope)
+void Heap::ObjectCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Object"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Object"));
}
ReturnedValue ObjectCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index d152bfd175..d74cd64926 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -25,7 +25,7 @@ namespace QV4 {
namespace Heap {
struct ObjectCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp
index 16cffea124..b8ede3e578 100644
--- a/src/qml/jsruntime/qv4promiseobject.cpp
+++ b/src/qml/jsruntime/qv4promiseobject.cpp
@@ -314,9 +314,9 @@ void Heap::PromiseReaction::triggerWithValue(ExecutionEngine *e, const Value *va
handler->addReaction(e, reaction, value);
}
-void Heap::PromiseCtor::init(QV4::ExecutionContext *scope)
+void Heap::PromiseCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Promise"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Promise"));
}
void Heap::PromiseObject::init(ExecutionEngine *e)
diff --git a/src/qml/jsruntime/qv4promiseobject_p.h b/src/qml/jsruntime/qv4promiseobject_p.h
index ca31f00881..fbde9f95e0 100644
--- a/src/qml/jsruntime/qv4promiseobject_p.h
+++ b/src/qml/jsruntime/qv4promiseobject_p.h
@@ -50,7 +50,7 @@ protected:
namespace Heap {
struct PromiseCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
#define PromiseObjectMembers(class, Member) \
diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp
index 109ab61059..974788d420 100644
--- a/src/qml/jsruntime/qv4proxy.cpp
+++ b/src/qml/jsruntime/qv4proxy.cpp
@@ -13,6 +13,7 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ProxyObject);
DEFINE_OBJECT_VTABLE(ProxyFunctionObject);
+DEFINE_OBJECT_VTABLE(ProxyConstructorObject);
void Heap::ProxyObject::init(const QV4::Object *target, const QV4::Object *handler)
{
@@ -25,12 +26,9 @@ void Heap::ProxyObject::init(const QV4::Object *target, const QV4::Object *handl
void Heap::ProxyFunctionObject::init(const QV4::FunctionObject *target, const QV4::Object *handler)
{
ExecutionEngine *e = internalClass->engine;
- FunctionObject::init(e->rootContext());
+ FunctionObject::init(e);
this->target.set(e, target->d());
this->handler.set(e, handler->d());
-
- if (!target->isConstructor())
- jsConstruct = nullptr;
}
@@ -643,7 +641,8 @@ OwnPropertyKeyIterator *ProxyObject::virtualOwnPropertyKeys(const Object *m, Val
}
-ReturnedValue ProxyFunctionObject::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
+ReturnedValue ProxyConstructorObject::virtualCallAsConstructor(
+ const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
{
Scope scope(f);
const ProxyObject *o = static_cast<const ProxyObject *>(f);
@@ -658,10 +657,8 @@ ReturnedValue ProxyFunctionObject::virtualCallAsConstructor(const FunctionObject
if (scope.hasException())
return Encode::undefined();
- if (trap->isNullOrUndefined()) {
- Q_ASSERT(target->isConstructor());
+ if (trap->isNullOrUndefined())
return target->callAsConstructor(argv, argc, newTarget);
- }
if (!trap->isFunctionObject())
return scope.engine->throwTypeError();
@@ -708,11 +705,11 @@ ReturnedValue ProxyFunctionObject::virtualCall(const FunctionObject *f, const Va
DEFINE_OBJECT_VTABLE(Proxy);
-void Heap::Proxy::init(QV4::ExecutionContext *ctx)
+void Heap::Proxy::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(ctx, QStringLiteral("Proxy"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Proxy"));
- Scope scope(ctx);
+ Scope scope(engine);
Scoped<QV4::Proxy> ctor(scope, this);
ctor->defineDefaultProperty(QStringLiteral("revocable"), QV4::Proxy::method_revocable, 2);
ctor->defineReadonlyConfigurableProperty(scope.engine->id_length(), Value::fromInt32(2));
@@ -734,9 +731,18 @@ ReturnedValue Proxy::virtualCallAsConstructor(const FunctionObject *f, const Val
return scope.engine->throwTypeError();
const FunctionObject *targetFunction = target->as<FunctionObject>();
- if (targetFunction)
- return scope.engine->memoryManager->allocate<ProxyFunctionObject>(targetFunction, handler)->asReturnedValue();
- return scope.engine->memoryManager->allocate<ProxyObject>(target, handler)->asReturnedValue();
+ if (!targetFunction) {
+ return scope.engine->memoryManager->allocate<ProxyObject>(target, handler)
+ ->asReturnedValue();
+ }
+
+ if (targetFunction->isConstructor()) {
+ return scope.engine->memoryManager->allocate<ProxyConstructorObject>(
+ targetFunction, handler)->asReturnedValue();
+ }
+
+ return scope.engine->memoryManager->allocate<ProxyFunctionObject>(targetFunction, handler)
+ ->asReturnedValue();
}
ReturnedValue Proxy::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
@@ -753,7 +759,10 @@ ReturnedValue Proxy::method_revocable(const FunctionObject *f, const Value *, co
Q_ASSERT(proxy);
ScopedString revoke(scope, scope.engine->newString(QStringLiteral("revoke")));
- ScopedFunctionObject revoker(scope, scope.engine->memoryManager->allocate<FunctionObject>(scope.engine->rootContext(), nullptr, method_revoke));
+ ScopedFunctionObject revoker(
+ scope,
+ scope.engine->memoryManager->allocate<DynamicFunctionObject>(
+ scope.engine, nullptr, method_revoke));
revoker->defineReadonlyConfigurableProperty(scope.engine->id_length(), Value::fromInt32(0));
revoker->defineDefaultProperty(scope.engine->symbol_revokableProxy(), proxy);
diff --git a/src/qml/jsruntime/qv4proxy_p.h b/src/qml/jsruntime/qv4proxy_p.h
index b3be05a11b..b3ce9c7a96 100644
--- a/src/qml/jsruntime/qv4proxy_p.h
+++ b/src/qml/jsruntime/qv4proxy_p.h
@@ -37,13 +37,15 @@ struct ProxyFunctionObject : ProxyObject {
void init(const QV4::FunctionObject *target, const QV4::Object *handler);
};
+struct ProxyConstructorObject : ProxyFunctionObject {};
+
#define ProxyMembers(class, Member) \
Member(class, Pointer, Symbol *, revokableProxySymbol) \
DECLARE_HEAP_OBJECT(Proxy, FunctionObject) {
DECLARE_MARKOBJECTS(Proxy)
- void init(QV4::ExecutionContext *ctx);
+ void init(ExecutionEngine *engine);
};
}
@@ -60,9 +62,6 @@ struct ProxyObject : FunctionObject {
V4_OBJECT2(ProxyObject, Object)
Q_MANAGED_TYPE(ProxyObject)
V4_INTERNALCLASS(ProxyObject)
- enum {
- IsFunctionObject = false
- };
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
@@ -81,14 +80,16 @@ struct ProxyFunctionObject : ProxyObject {
V4_OBJECT2(ProxyFunctionObject, FunctionObject)
Q_MANAGED_TYPE(ProxyObject)
V4_INTERNALCLASS(ProxyFunctionObject)
- enum {
- IsFunctionObject = true
- };
- static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *);
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
+struct ProxyConstructorObject : ProxyFunctionObject {
+ V4_OBJECT2(ProxyConstructorObject, ProxyFunctionObject)
+
+ static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *);
+};
+
struct Proxy : FunctionObject
{
V4_OBJECT2(Proxy, FunctionObject)
diff --git a/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp b/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp
index 13d93c7122..6521c98dbf 100644
--- a/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp
@@ -16,38 +16,15 @@ namespace QV4 {
void Heap::QMetaObjectWrapper::init(const QMetaObject *metaObject)
{
FunctionObject::init();
- this->metaObject = metaObject;
- constructors = nullptr;
- constructorCount = 0;
+ m_metaObject = metaObject;
}
void Heap::QMetaObjectWrapper::destroy()
{
- delete[] constructors;
+ delete[] m_constructors;
+ FunctionObject::destroy();
}
-void Heap::QMetaObjectWrapper::ensureConstructorsCache() {
-
- const int count = metaObject->constructorCount();
- if (constructorCount != count) {
- delete[] constructors;
- constructorCount = count;
- if (count == 0) {
- constructors = nullptr;
- return;
- }
- constructors = new QQmlPropertyData[count];
-
- for (int i = 0; i < count; ++i) {
- QMetaMethod method = metaObject->constructor(i);
- QQmlPropertyData &d = constructors[i];
- d.load(method);
- d.setCoreIndex(i);
- }
- }
-}
-
-
ReturnedValue QMetaObjectWrapper::create(ExecutionEngine *engine, const QMetaObject* metaObject) {
Scope scope(engine);
@@ -57,7 +34,7 @@ ReturnedValue QMetaObjectWrapper::create(ExecutionEngine *engine, const QMetaObj
}
void QMetaObjectWrapper::init(ExecutionEngine *) {
- const QMetaObject & mo = *d()->metaObject;
+ const QMetaObject &mo = *d()->metaObject();
for (int i = 0; i < mo.enumeratorCount(); i++) {
QMetaEnum Enum = mo.enumerator(i);
@@ -71,41 +48,49 @@ void QMetaObjectWrapper::init(ExecutionEngine *) {
ReturnedValue QMetaObjectWrapper::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *)
{
- const QMetaObjectWrapper *This = static_cast<const QMetaObjectWrapper*>(f);
- return This->constructInternal(argv, argc);
+ Q_ASSERT(f->as<QMetaObjectWrapper>());
+ return construct(static_cast<const QMetaObjectWrapper*>(f)->d(), argv, argc);
}
-ReturnedValue QMetaObjectWrapper::constructInternal(const Value *argv, int argc) const
+ReturnedValue QMetaObjectWrapper::constructInternal(
+ const QMetaObject *mo, const QQmlPropertyData *constructors, Heap::FunctionObject *d,
+ const Value *argv, int argc)
{
+ ExecutionEngine *v4 = d->internalClass->engine;
- d()->ensureConstructorsCache();
-
- ExecutionEngine *v4 = engine();
- const QMetaObject* mo = d()->metaObject;
- if (d()->constructorCount == 0) {
+ if (!constructors) {
return v4->throwTypeError(QLatin1String(mo->className())
+ QLatin1String(" has no invokable constructor"));
}
Scope scope(v4);
- Scoped<QObjectWrapper> object(scope);
+ ScopedObject object(scope);
JSCallData cData(nullptr, argv, argc);
CallData *callData = cData.callData(scope);
const QQmlObjectOrGadget objectOrGadget(mo);
- if (d()->constructorCount == 1) {
+ const auto callType = [](QMetaType metaType) {
+ return metaType.flags() & QMetaType::PointerToQObject
+ ? QMetaObject::CreateInstance
+ : QMetaObject::ConstructInPlace;
+ };
+
+ const int constructorCount = mo->constructorCount();
+ if (constructorCount == 1) {
object = QObjectMethod::callPrecise(
- objectOrGadget, d()->constructors[0], v4, callData, QMetaObject::CreateInstance);
+ objectOrGadget, constructors[0], v4, callData,
+ callType(constructors[0].propType()));
} else if (const QQmlPropertyData *ctor = QObjectMethod::resolveOverloaded(
- objectOrGadget, d()->constructors, d()->constructorCount, v4, callData)) {
+ objectOrGadget, constructors, constructorCount, v4, callData)) {
object = QObjectMethod::callPrecise(
- objectOrGadget, *ctor, v4, callData, QMetaObject::CreateInstance);
+ objectOrGadget, *ctor, v4, callData, callType(ctor->propType()));
}
+
if (object) {
- Scoped<QMetaObjectWrapper> metaObject(scope, this);
- object->defineDefaultProperty(v4->id_constructor(), metaObject);
- object->setPrototypeOf(const_cast<QMetaObjectWrapper*>(this));
+ Scoped<FunctionObject> functionObject(scope, d);
+ object->defineDefaultProperty(v4->id_constructor(), functionObject);
+ object->setPrototypeOf(functionObject);
}
return object.asReturnedValue();
diff --git a/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h b/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h
index 063bc089e7..c44b18f291 100644
--- a/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h
@@ -27,14 +27,57 @@ class QQmlPropertyData;
namespace QV4 {
namespace Heap {
-struct QMetaObjectWrapper : FunctionObject {
- const QMetaObject* metaObject;
- QQmlPropertyData *constructors;
- int constructorCount;
-
- void init(const QMetaObject* metaObject);
+struct QMetaObjectWrapper : FunctionObject
+{
+ void init(const QMetaObject *metaObject);
void destroy();
- void ensureConstructorsCache();
+
+ const QMetaObject *metaObject() const { return m_metaObject; }
+ QMetaType metaType() const
+ {
+ const QMetaType type = m_metaObject->metaType();
+ if (type.flags() & QMetaType::IsGadget)
+ return type;
+
+ // QObject* is our best guess because we can't get from a metatype to
+ // the metatype of its pointer.
+ return QMetaType::fromType<QObject *>();
+ }
+
+ const QQmlPropertyData *ensureConstructorsCache(
+ const QMetaObject *metaObject, QMetaType metaType)
+ {
+ Q_ASSERT(metaObject);
+ if (!m_constructors)
+ m_constructors = createConstructors(metaObject, metaType);
+ return m_constructors;
+ }
+
+
+ static const QQmlPropertyData *createConstructors(
+ const QMetaObject *metaObject, QMetaType metaType)
+ {
+ Q_ASSERT(metaObject);
+ const int count = metaObject->constructorCount();
+ if (count == 0)
+ return nullptr;
+
+ QQmlPropertyData *constructors = new QQmlPropertyData[count];
+
+ for (int i = 0; i < count; ++i) {
+ QMetaMethod method = metaObject->constructor(i);
+ QQmlPropertyData &d = constructors[i];
+ d.load(method);
+ d.setPropType(metaType);
+ d.setCoreIndex(i);
+ }
+
+ return constructors;
+ }
+
+private:
+ const QMetaObject *m_metaObject;
+ const QQmlPropertyData *m_constructors;
};
} // namespace Heap
@@ -45,7 +88,15 @@ struct Q_QML_EXPORT QMetaObjectWrapper : public FunctionObject
V4_NEEDS_DESTROY
static ReturnedValue create(ExecutionEngine *engine, const QMetaObject* metaObject);
- const QMetaObject *metaObject() const { return d()->metaObject; }
+ const QMetaObject *metaObject() const { return d()->metaObject(); }
+
+ template<typename HeapObject>
+ ReturnedValue static construct(HeapObject *d, const Value *argv, int argc)
+ {
+ const QMetaObject *mo = d->metaObject();
+ return constructInternal(
+ mo, d->ensureConstructorsCache(mo, d->metaType()), d, argv, argc);
+ }
protected:
static ReturnedValue virtualCallAsConstructor(
@@ -54,7 +105,10 @@ protected:
private:
void init(ExecutionEngine *engine);
- ReturnedValue constructInternal(const Value *argv, int argc) const;
+
+ static ReturnedValue constructInternal(
+ const QMetaObject *mo, const QQmlPropertyData *constructors, Heap::FunctionObject *d,
+ const Value *argv, int argc);
};
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 5f85aae89e..eaee078a5f 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -3,61 +3,53 @@
#include "qv4qobjectwrapper_p.h"
-#include <private/qqmlobjectorgadget_p.h>
-#include <private/qqmlengine_p.h>
-#include <private/qqmlvmemetaobject_p.h>
-#include <private/qqmlbinding_p.h>
#include <private/qjsvalue_p.h>
-#include <private/qqmlexpression_p.h>
-#include <private/qqmlglobal_p.h>
+
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlobjectorgadget_p.h>
+#include <private/qqmlpropertybinding_p.h>
+#include <private/qqmlscriptstring_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <private/qqmltypewrapper_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
-#include <private/qqmllistwrapper_p.h>
-#include <private/qqmlbuiltinfunctions_p.h>
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
-#endif
+#include <private/qqmlvmemetaobject_p.h>
#include <private/qv4arraybuffer_p.h>
+#include <private/qv4compileddata_p.h>
+#include <private/qv4dateobject_p.h>
#include <private/qv4functionobject_p.h>
-#include <private/qv4runtime_p.h>
-#include <private/qv4variantobject_p.h>
#include <private/qv4identifiertable_p.h>
-#include <private/qv4lookup_p.h>
-#include <private/qv4qmlcontext_p.h>
-#include <private/qv4sequenceobject_p.h>
-#include <private/qv4objectproto_p.h>
+#include <private/qv4jscall_p.h>
#include <private/qv4jsonobject_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4mm_p.h>
#include <private/qv4regexpobject_p.h>
-#include <private/qv4dateobject_p.h>
+#include <private/qv4runtime_p.h>
#include <private/qv4scopedvalue_p.h>
-#include <private/qv4jscall_p.h>
-#include <private/qv4mm_p.h>
-#include <private/qqmlscriptstring_p.h>
-#include <private/qv4compileddata_p.h>
-#include <private/qqmlpropertybinding_p.h>
-#include <private/qqmlpropertycachemethodarguments_p.h>
-#include <private/qqmlsignalnames_p.h>
+#include <private/qv4sequenceobject_p.h>
+#include <private/qv4variantobject_p.h>
-#include <QtQml/qjsvalue.h>
#include <QtCore/qjsonarray.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonvalue.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qatomic.h>
-#include <QtCore/qmetaobject.h>
-#if QT_CONFIG(qml_itemmodel)
-#include <QtCore/qabstractitemmodel.h>
-#endif
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qqueue.h>
+#include <QtCore/qtimer.h>
#include <QtCore/qtypes.h>
+#include <QtCore/qvarlengtharray.h>
#include <vector>
+
+#if QT_CONFIG(qml_itemmodel)
+#include <QtCore/qabstractitemmodel.h>
+#endif
+
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
+Q_LOGGING_CATEGORY(lcBuiltinsBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
Q_LOGGING_CATEGORY(lcObjectConnect, "qt.qml.object.connect", QtWarningMsg)
Q_LOGGING_CATEGORY(lcOverloadResolution, "qt.qml.overloadresolution", QtWarningMsg)
Q_LOGGING_CATEGORY(lcMethodBehavior, "qt.qml.method.behavior")
@@ -246,11 +238,8 @@ static ReturnedValue loadProperty(
property.readProperty(object, &v);
return QV4::JsonObject::fromJsonObject(v4, v);
}
- case QMetaType::QJsonArray: {
- QJsonArray v;
- property.readProperty(object, &v);
- return QV4::JsonObject::fromJsonArray(v4, v);
- }
+ case QMetaType::QJsonArray:
+ return encodeSequence(QMetaSequence::fromContainer<QJsonArray>());
case QMetaType::QStringList:
return encodeSequence(QMetaSequence::fromContainer<QStringList>());
case QMetaType::QVariantList:
@@ -360,20 +349,15 @@ ReturnedValue QObjectWrapper::getProperty(
Q_ASSERT(vmemo);
return vmemo->vmeMethod(property->coreIndex());
} else if (property->isV4Function()) {
- Scope scope(engine);
- ScopedContext global(scope, engine->qmlContext());
- if (!global)
- global = engine->rootContext();
return QObjectMethod::create(
- global, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
+ engine, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
} else if (property->isSignalHandler()) {
QmlSignalHandler::initProto(engine);
return engine->memoryManager->allocate<QmlSignalHandler>(
object, property->coreIndex())->asReturnedValue();
} else {
- ExecutionContext *global = engine->rootContext();
return QObjectMethod::create(
- global, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
+ engine, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
}
}
@@ -405,8 +389,7 @@ static OptionalReturnedValue getDestroyOrToStringMethod(
if (hasProperty)
*hasProperty = true;
- ExecutionContext *global = v4->rootContext();
- return OptionalReturnedValue(QObjectMethod::create(global, qobj, index));
+ return OptionalReturnedValue(QObjectMethod::create(v4, qobj, index));
}
static OptionalReturnedValue getPropertyFromImports(
@@ -608,7 +591,9 @@ void QObjectWrapper::setProperty(
Scope scope(engine);
if (ScopedFunctionObject f(scope, value); f) {
- if (!f->isBinding()) {
+ if (f->as<QQmlTypeWrapper>()) {
+ // Ignore. It's probably a singleton or an attached type.
+ } else if (!f->isBinding()) {
const bool isAliasToAllowed = [&]() {
if (property->isAlias()) {
const QQmlPropertyIndex originalIndex(property->coreIndex(), -1);
@@ -641,7 +626,7 @@ void QObjectWrapper::setProperty(
QQmlRefPointer<QQmlContextData> callingQmlContext = scope.engine->callingQmlContext();
Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
- ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
+ Scoped<JavaScriptFunctionObject> f(scope, bindingFunction->bindingFunction());
ScopedContext ctx(scope, f->scope());
// binding assignment.
@@ -679,13 +664,13 @@ void QObjectWrapper::setProperty(
}
}
- if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
+ if (Q_UNLIKELY(lcBuiltinsBindingRemoval().isInfoEnabled())) {
if (auto binding = QQmlPropertyPrivate::binding(object, QQmlPropertyIndex(property->coreIndex()))) {
const auto stackFrame = engine->currentStackFrame;
switch (binding->kind()) {
case QQmlAbstractBinding::QmlBinding: {
const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
- qCInfo(lcBindingRemoval,
+ qCInfo(lcBuiltinsBindingRemoval,
"Overwriting binding on %s::%s at %s:%d that was initially bound at %s",
object->metaObject()->className(), qPrintable(property->name(object)),
qPrintable(stackFrame->source()), stackFrame->lineNumber(),
@@ -694,7 +679,7 @@ void QObjectWrapper::setProperty(
}
case QQmlAbstractBinding::ValueTypeProxy:
case QQmlAbstractBinding::PropertyToPropertyBinding: {
- qCInfo(lcBindingRemoval,
+ qCInfo(lcBuiltinsBindingRemoval,
"Overwriting binding on %s::%s at %s:%d",
object->metaObject()->className(), qPrintable(property->name(object)),
qPrintable(stackFrame->source()), stackFrame->lineNumber());
@@ -722,7 +707,9 @@ void QObjectWrapper::setProperty(
const QMetaType propType = property->propType();
// functions are already handled, except for the QJSValue case
- Q_ASSERT(!value.as<FunctionObject>() || propType == QMetaType::fromType<QJSValue>());
+ Q_ASSERT(!value.as<FunctionObject>()
+ || value.as<QV4::QQmlTypeWrapper>()
+ || propType == QMetaType::fromType<QJSValue>());
if (value.isNull() && property->isQObject()) {
PROPERTY_STORE(QObject*, nullptr);
@@ -2559,21 +2546,22 @@ ReturnedValue CallArgument::toValue(ExecutionEngine *engine)
return Encode::undefined();
}
-ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::Object *wrapper, int index)
+ReturnedValue QObjectMethod::create(ExecutionEngine *engine, Heap::Object *wrapper, int index)
{
- Scope valueScope(scope);
+ Scope valueScope(engine);
Scoped<QObjectMethod> method(
valueScope,
- valueScope.engine->memoryManager->allocate<QObjectMethod>(scope, wrapper, index));
+ engine->memoryManager->allocate<QObjectMethod>(engine, wrapper, index));
return method.asReturnedValue();
}
-ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index)
+ReturnedValue QObjectMethod::create(
+ ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *valueType, int index)
{
- Scope valueScope(scope);
+ Scope valueScope(engine);
Scoped<QObjectMethod> method(
valueScope,
- valueScope.engine->memoryManager->allocate<QObjectMethod>(scope, valueType, index));
+ engine->memoryManager->allocate<QObjectMethod>(engine, valueType, index));
return method.asReturnedValue();
}
@@ -2596,11 +2584,10 @@ ReturnedValue QObjectMethod::create(
}
}
- Scoped<ExecutionContext> context(valueScope, cloneFrom->scope.get());
Scoped<QObjectMethod> method(
valueScope,
engine->memoryManager->allocate<QV4::QObjectMethod>(
- context, valueTypeWrapper ? valueTypeWrapper->d() : object, cloneFrom->index));
+ engine, valueTypeWrapper ? valueTypeWrapper->d() : object, cloneFrom->index));
method->d()->methodCount = cloneFrom->methodCount;
@@ -2626,10 +2613,10 @@ ReturnedValue QObjectMethod::create(
return method.asReturnedValue();
}
-void Heap::QObjectMethod::init(QV4::ExecutionContext *scope, Object *object, int methodIndex)
+void Heap::QObjectMethod::init(QV4::ExecutionEngine *engine, Object *object, int methodIndex)
{
- Heap::FunctionObject::init(scope);
- wrapper.set(internalClass->engine, object);
+ Heap::FunctionObject::init(engine);
+ wrapper.set(engine, object);
index = methodIndex;
}
@@ -3106,7 +3093,7 @@ ReturnedValue QmlSignalHandler::call(const Value *thisObject, const Value *argv,
Scope scope(engine());
Scoped<QObjectMethod> method(
scope, QObjectMethod::create(
- scope.engine->rootContext(),
+ scope.engine,
static_cast<Heap::QObjectWrapper *>(nullptr),
signalIndex()));
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 1af8fc887f..288585f844 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -72,7 +72,7 @@ DECLARE_EXPORTED_HEAP_OBJECT(QObjectMethod, FunctionObject) {
int methodCount;
int index;
- void init(QV4::ExecutionContext *scope, Object *wrapper, int index);
+ void init(QV4::ExecutionEngine *engine, Object *wrapper, int index);
void destroy()
{
if (methods != reinterpret_cast<const QQmlPropertyData *>(&_singleMethod))
@@ -348,10 +348,11 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
enum { DestroyMethod = -1, ToStringMethod = -2 };
- static ReturnedValue create(QV4::ExecutionContext *scope, Heap::Object *wrapper, int index);
+ static ReturnedValue create(ExecutionEngine *engine, Heap::Object *wrapper, int index);
static ReturnedValue create(
- QV4::ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index);
- static ReturnedValue create(QV4::ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
+ ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *valueType, int index);
+ static ReturnedValue create(
+ ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
Heap::Object *wrapper, Heap::Object *object);
int methodIndex() const { return d()->index; }
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index acb9f0acfc..144cd39bcd 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -195,9 +195,9 @@ ReturnedValue RegExpObject::builtinExec(ExecutionEngine *engine, const String *s
DEFINE_OBJECT_VTABLE(RegExpCtor);
-void Heap::RegExpCtor::init(QV4::ExecutionContext *scope)
+void Heap::RegExpCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("RegExp"));
+ Heap::FunctionObject::init(engine, QStringLiteral("RegExp"));
clearLastMatch();
}
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 8d52300013..179a01fb45 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -50,7 +50,7 @@ DECLARE_HEAP_OBJECT(RegExpObject, Object) {
DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) {
DECLARE_MARKOBJECTS(RegExpCtor)
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
void clearLastMatch();
};
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index c51c94ffe4..5977360080 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -41,6 +41,8 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcCoercingTypeAssertion, "qt.qml.coercingTypeAssertion");
+
namespace QV4 {
#ifdef QV4_COUNT_RUNTIME_FUNCTIONS
@@ -380,11 +382,42 @@ QV4::ReturnedValue Runtime::As::call(ExecutionEngine *engine, const Value &lval,
else if (result->isBoolean())
return Encode::null();
+ if (engine->callingQmlContext()->valueTypesAreAssertable())
+ return Encode::undefined();
+
// Try to convert the value type
- if (Scoped<QQmlTypeWrapper> typeWrapper(scope, rval); typeWrapper)
- return coerce(engine, lval, typeWrapper->d()->type(), false);
+ Scoped<QQmlTypeWrapper> typeWrapper(scope, rval);
+ if (!typeWrapper)
+ return Encode::undefined();
- return Encode::undefined();
+ const auto *stackFrame = engine->currentStackFrame;
+ if (lval.as<QQmlValueTypeWrapper>()) {
+ qCWarning(lcCoercingTypeAssertion).nospace().noquote()
+ << stackFrame->source() << ':' << stackFrame->lineNumber() << ':'
+ << " Coercing between incompatible value types mistakenly yields null rather than"
+ << " undefined. Add 'pragma ValueTypeBehavior: Assertable' to prevent this.";
+ return Encode::null();
+ }
+
+ if (lval.as<QV4::QObjectWrapper>()) {
+ qCWarning(lcCoercingTypeAssertion).nospace().noquote()
+ << stackFrame->source() << ':' << stackFrame->lineNumber() << ':'
+ << " Coercing from instances of object types to value types mistakenly yields null"
+ << " rather than undefined. Add 'pragma ValueTypeBehavior: Assertable' to prevent"
+ << " this.";
+ return Encode::null();
+ }
+
+ result = coerce(engine, lval, typeWrapper->d()->type(), false);
+ if (result->isUndefined())
+ return Encode::undefined();
+
+ qCWarning(lcCoercingTypeAssertion).nospace().noquote()
+ << stackFrame->source() << ':' << stackFrame->lineNumber() << ':'
+ << " Coercing a value to " << typeWrapper->toQStringNoThrow()
+ << " using a type assertion. This behavior is deprecated."
+ << " Add 'pragma ValueTypeBehavior: Assertable' to prevent it.";
+ return result->asReturnedValue();
}
QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left, const Value &right)
@@ -1029,7 +1062,7 @@ ReturnedValue Runtime::LoadName::call(ExecutionEngine *engine, int nameIndex)
static Object *getSuperBase(Scope &scope)
{
- ScopedFunctionObject f(scope);
+ Scoped<JavaScriptFunctionObject> f(scope);
ScopedObject homeObject(scope);
if (scope.engine->currentStackFrame->isJSTypesFrame()) {
JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(
@@ -1188,7 +1221,7 @@ ReturnedValue Runtime::LoadSuperConstructor::call(ExecutionEngine *engine, const
if (!f)
return engine->throwTypeError();
Heap::Object *c = static_cast<const Object &>(t).getPrototypeOf();
- if (!c->vtable()->isFunctionObject || !static_cast<Heap::FunctionObject *>(c)->isConstructor())
+ if (!c->vtable()->callAsConstructor)
return engine->throwTypeError();
return c->asReturnedValue();
}
@@ -1627,20 +1660,23 @@ ReturnedValue Runtime::TailCall::call(JSTypesStackFrame *frame, ExecutionEngine
int argc = tos[StackOffsets::tailCall_argc].int_32();
Q_ASSERT(argc >= 0);
- if (!function.isFunctionObject())
+ const JavaScriptFunctionObject *jsfo = function.as<JavaScriptFunctionObject>();
+ if (!jsfo) {
+ if (const FunctionObject *fo = function.as<FunctionObject>())
+ return checkedResult(engine, fo->call(&thisObject, argv, argc));
return engine->throwTypeError();
+ }
- const FunctionObject &fo = static_cast<const FunctionObject &>(function);
- if (!frame->callerCanHandleTailCall() || !fo.canBeTailCalled() || engine->debugger()
- || unsigned(argc) > fo.formalParameterCount()) {
+ if (!frame->callerCanHandleTailCall() || !jsfo->canBeTailCalled() || engine->debugger()
+ || unsigned(argc) > jsfo->formalParameterCount()) {
// Cannot tailcall, do a normal call:
- return checkedResult(engine, fo.call(&thisObject, argv, argc));
+ return checkedResult(engine, jsfo->call(&thisObject, argv, argc));
}
memmove(frame->jsFrame->args, argv, argc * sizeof(Value));
- frame->init(fo.function(), frame->jsFrame->argValues<Value>(), argc,
+ frame->init(jsfo->function(), frame->jsFrame->argValues<Value>(), argc,
frame->callerCanHandleTailCall());
- frame->setupJSFrame(frame->framePointer(), fo, fo.scope(), thisObject,
+ frame->setupJSFrame(frame->framePointer(), *jsfo, jsfo->scope(), thisObject,
Primitive::undefinedValue());
engine->jsStackTop = frame->framePointer() + frame->requiredJSStackFrameSize();
frame->setPendingTailCall(true);
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index cc899428c2..8de85a86bf 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -42,25 +42,6 @@ static ReturnedValue doGetIndexed(const Sequence *s, qsizetype index) {
return v->asReturnedValue();
}
-template<typename Compare>
-void sortSequence(Sequence *sequence, const Compare &compare)
-{
- /* non-const */ Heap::Sequence *p = sequence->d();
-
- QSequentialIterable iterable(p->metaSequence(), p->listType(), p->storagePointer());
- if (iterable.canRandomAccessIterate()) {
- std::sort(QSequentialIterable::RandomAccessIterator(iterable.mutableBegin()),
- QSequentialIterable::RandomAccessIterator(iterable.mutableEnd()),
- compare);
- } else if (iterable.canReverseIterate()) {
- std::sort(QSequentialIterable::BidirectionalIterator(iterable.mutableBegin()),
- QSequentialIterable::BidirectionalIterator(iterable.mutableEnd()),
- compare);
- } else {
- qWarning() << "Container has no suitable iterator for sorting";
- }
-}
-
// helper function to generate valid warnings if errors occur during sequence operations.
static void generateWarning(QV4::ExecutionEngine *v4, const QString& description)
{
@@ -108,40 +89,6 @@ struct SequenceOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
}
};
-struct SequenceCompareFunctor
-{
- SequenceCompareFunctor(QV4::ExecutionEngine *v4, const QV4::Value &compareFn)
- : m_v4(v4), m_compareFn(&compareFn)
- {}
-
- bool operator()(const QVariant &lhs, const QVariant &rhs)
- {
- QV4::Scope scope(m_v4);
- ScopedFunctionObject compare(scope, m_compareFn);
- if (!compare)
- return m_v4->throwTypeError();
- Value *argv = scope.alloc(2);
- argv[0] = m_v4->fromVariant(lhs);
- argv[1] = m_v4->fromVariant(rhs);
- QV4::ScopedValue result(scope, compare->call(m_v4->globalObject, argv, 2));
- if (scope.hasException())
- return false;
- return result->toNumber() < 0;
- }
-
-private:
- QV4::ExecutionEngine *m_v4;
- const QV4::Value *m_compareFn;
-};
-
-struct SequenceDefaultCompareFunctor
-{
- bool operator()(const QVariant &lhs, const QVariant &rhs)
- {
- return lhs.toString() < rhs.toString();
- }
-};
-
void Heap::Sequence::initTypes(QMetaType listType, QMetaSequence metaSequence)
{
m_listType = listType.iface();
@@ -250,6 +197,42 @@ QVariant Sequence::at(qsizetype index) const
return result;
}
+QVariant Sequence::shift()
+{
+ auto *p = d();
+ void *storage = p->storagePointer();
+ Q_ASSERT(storage); // Must readReference() before
+ const QMetaType v = p->valueMetaType();
+ const QMetaSequence m = p->metaSequence();
+
+ const auto variantData = [&](QVariant *variant) -> void *{
+ if (v == QMetaType::fromType<QVariant>())
+ return variant;
+
+ *variant = QVariant(v);
+ return variant->data();
+ };
+
+ QVariant result;
+ void *resultData = variantData(&result);
+ m.valueAtIndex(storage, 0, resultData);
+
+ if (m.canRemoveValueAtBegin()) {
+ m.removeValueAtBegin(storage);
+ return result;
+ }
+
+ QVariant t;
+ void *tData = variantData(&t);
+ for (qsizetype i = 1, end = m.size(storage); i < end; ++i) {
+ m.valueAtIndex(storage, i, tData);
+ m.setValueAtIndex(storage, i - 1, tData);
+ }
+ m.removeValueAtEnd(storage);
+
+ return result;
+}
+
template<typename Action>
void convertAndDo(const QVariant &item, const QMetaType v, Action action)
@@ -404,24 +387,6 @@ bool Sequence::containerIsEqualTo(Managed *other)
return false;
}
-bool Sequence::sort(const FunctionObject *f, const Value *, const Value *argv, int argc)
-{
- if (d()->isReadOnly())
- return false;
- if (d()->isReference() && !loadReference())
- return false;
-
- if (argc == 1 && argv[0].as<FunctionObject>())
- sortSequence(this, SequenceCompareFunctor(f->engine(), argv[0]));
- else
- sortSequence(this, SequenceDefaultCompareFunctor());
-
- if (d()->object())
- storeReference();
-
- return true;
-}
-
void *Sequence::getRawContainerPtr() const
{ return d()->storagePointer(); }
@@ -599,9 +564,9 @@ static QV4::ReturnedValue method_set_length(const FunctionObject *f, const Value
void SequencePrototype::init()
{
- defineDefaultProperty(QStringLiteral("sort"), method_sort, 1);
defineDefaultProperty(engine()->id_valueOf(), method_valueOf, 0);
defineAccessorProperty(QStringLiteral("length"), method_get_length, method_set_length);
+ defineDefaultProperty(QStringLiteral("shift"), method_shift, 0);
}
ReturnedValue SequencePrototype::method_valueOf(const FunctionObject *f, const Value *thisObject, const Value *, int)
@@ -609,22 +574,27 @@ ReturnedValue SequencePrototype::method_valueOf(const FunctionObject *f, const V
return Encode(thisObject->toString(f->engine()));
}
-ReturnedValue SequencePrototype::method_sort(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue SequencePrototype::method_shift(
+ const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(b);
- QV4::ScopedObject o(scope, thisObject);
- if (!o || !o->isV4SequenceType())
- THROW_TYPE_ERROR();
+ Scoped<Sequence> s(scope, thisObject);
+ if (!s)
+ return ArrayPrototype::method_shift(b, thisObject, argv, argc);
- if (argc >= 2)
- return o.asReturnedValue();
+ if (s->d()->isReference() && !s->loadReference())
+ RETURN_UNDEFINED();
- if (auto *s = o->as<Sequence>()) {
- if (!s->sort(b, thisObject, argv, argc))
- THROW_TYPE_ERROR();
- }
+ const qsizetype len = s->size();
+ if (!len)
+ RETURN_UNDEFINED();
+
+ ScopedValue result(scope, scope.engine->fromVariant(s->shift()));
+
+ if (s->d()->object())
+ s->storeReference();
- return o.asReturnedValue();
+ return result->asReturnedValue();
}
ReturnedValue SequencePrototype::newSequence(
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index 3d1baf6c77..0908e52574 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -34,7 +34,7 @@ struct Q_QML_EXPORT SequencePrototype : public QV4::Object
void init();
static ReturnedValue method_valueOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_sort(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_shift(const FunctionObject *b, const Value *thisObject, const Value *, int);
static ReturnedValue newSequence(
QV4::ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data,
@@ -101,6 +101,7 @@ public:
qsizetype size() const;
QVariant at(qsizetype index) const;
+ QVariant shift();
void append(const QVariant &item);
void append(qsizetype num, const QVariant &item);
void replace(qsizetype index, const QVariant &item);
@@ -110,7 +111,6 @@ public:
bool containerPutIndexed(qsizetype index, const QV4::Value &value);
bool containerDeleteIndexedProperty(qsizetype index);
bool containerIsEqualTo(Managed *other);
- bool sort(const FunctionObject *f, const Value *, const Value *argv, int argc);
void *getRawContainerPtr() const;
bool loadReference() const;
bool storeReference();
diff --git a/src/qml/jsruntime/qv4setobject.cpp b/src/qml/jsruntime/qv4setobject.cpp
index a7589a40db..de2c378558 100644
--- a/src/qml/jsruntime/qv4setobject.cpp
+++ b/src/qml/jsruntime/qv4setobject.cpp
@@ -14,14 +14,14 @@ DEFINE_OBJECT_VTABLE(SetCtor);
DEFINE_OBJECT_VTABLE(WeakSetCtor);
DEFINE_OBJECT_VTABLE(SetObject);
-void Heap::WeakSetCtor::init(QV4::ExecutionContext *scope)
+void Heap::WeakSetCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("WeakSet"));
+ Heap::FunctionObject::init(engine, QStringLiteral("WeakSet"));
}
-void Heap::SetCtor::init(QV4::ExecutionContext *scope)
+void Heap::SetCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Set"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Set"));
}
ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget, bool isWeak)
@@ -104,6 +104,12 @@ ReturnedValue WeakSetPrototype::method_add(const FunctionObject *b, const Value
(!argc || !argv[0].isObject()))
return scope.engine->throwTypeError();
+ QV4::WriteBarrier::markCustom(scope.engine, [&](QV4::MarkStack *ms) {
+ if (scope.engine->memoryManager->gcStateMachine->state <= GCState::FreeWeakSets)
+ return;
+ argv[0].heapObject()->mark(ms);
+ });
+
that->d()->esTable->set(argv[0], Value::undefinedValue());
return that.asReturnedValue();
}
@@ -192,6 +198,10 @@ ReturnedValue SetPrototype::method_add(const FunctionObject *b, const Value *thi
if (!that || that->d()->isWeakSet)
return scope.engine->throwTypeError();
+ QV4::WriteBarrier::markCustom(scope.engine, [&](QV4::MarkStack *ms) {
+ argv[0].heapObject()->mark(ms);
+ });
+
that->d()->esTable->set(argv[0], Value::undefinedValue());
return that.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4setobject_p.h b/src/qml/jsruntime/qv4setobject_p.h
index 6ed44b4ed9..118cdebd5a 100644
--- a/src/qml/jsruntime/qv4setobject_p.h
+++ b/src/qml/jsruntime/qv4setobject_p.h
@@ -29,12 +29,12 @@ class ESTable;
namespace Heap {
struct WeakSetCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct SetCtor : WeakSetCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct SetObject : Object {
@@ -79,7 +79,7 @@ struct WeakSetPrototype : Object
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_add(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ Q_AUTOTEST_EXPORT static ReturnedValue method_add(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_delete(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_has(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
@@ -89,7 +89,7 @@ struct SetPrototype : WeakSetPrototype
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_add(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ Q_AUTOTEST_EXPORT static ReturnedValue method_add(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_clear(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_delete(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_entries(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index ad3c39c7b9..5f3d833f33 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -131,9 +131,9 @@ PropertyAttributes StringObject::virtualGetOwnProperty(const Managed *m, Propert
DEFINE_OBJECT_VTABLE(StringCtor);
-void Heap::StringCtor::init(QV4::ExecutionContext *scope)
+void Heap::StringCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("String"));
+ Heap::FunctionObject::init(engine, QStringLiteral("String"));
}
ReturnedValue StringCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index 451a989ef4..73c2bd7b34 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -44,7 +44,7 @@ DECLARE_HEAP_OBJECT(StringObject, Object) {
};
struct StringCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4symbol.cpp b/src/qml/jsruntime/qv4symbol.cpp
index 5f7ec89fd2..85ef57f680 100644
--- a/src/qml/jsruntime/qv4symbol.cpp
+++ b/src/qml/jsruntime/qv4symbol.cpp
@@ -19,9 +19,9 @@ void Heap::Symbol::init(const QString &s)
identifier = PropertyKey::fromStringOrSymbol(internalClass->engine, this);
}
-void Heap::SymbolCtor::init(QV4::ExecutionContext *scope)
+void Heap::SymbolCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Symbol"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Symbol"));
}
void Heap::SymbolObject::init(const QV4::Symbol *s)
diff --git a/src/qml/jsruntime/qv4symbol_p.h b/src/qml/jsruntime/qv4symbol_p.h
index e56510bd69..29a0189b69 100644
--- a/src/qml/jsruntime/qv4symbol_p.h
+++ b/src/qml/jsruntime/qv4symbol_p.h
@@ -25,7 +25,7 @@ namespace QV4 {
namespace Heap {
struct SymbolCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct Symbol : StringOrSymbol {
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index 6c72eaba5f..9c752f43bb 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -236,9 +236,9 @@ const TypedArrayOperations operations[NTypedArrayTypes] = {
};
-void Heap::TypedArrayCtor::init(QV4::ExecutionContext *scope, TypedArray::Type t)
+void Heap::TypedArrayCtor::init(QV4::ExecutionEngine *engine, TypedArray::Type t)
{
- Heap::FunctionObject::init(scope, QLatin1String(operations[t].name));
+ Heap::FunctionObject::init(engine, QLatin1String(operations[t].name));
type = t;
}
@@ -762,8 +762,6 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_fill(const FunctionObject *b,
fin = static_cast<uint>(std::min(relativeEnd, dlen));
}
- double val = argc ? argv[0].toNumber() : std::numeric_limits<double>::quiet_NaN();
- Value value = Value::fromDouble(val);
if (scope.hasException() || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
@@ -771,6 +769,14 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_fill(const FunctionObject *b,
uint bytesPerElement = v->bytesPerElement();
uint byteOffset = v->byteOffset();
+ Value value;
+ if (!argc)
+ value.setDouble(std::numeric_limits<double>::quiet_NaN());
+ else if (argv[0].isNumber())
+ value = argv[0];
+ else
+ value.setDouble(argv[0].toNumber());
+
while (k < fin) {
v->d()->type->write(data + byteOffset + k * bytesPerElement, value);
k++;
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index 9747eac411..50db9610c7 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -90,7 +90,7 @@ struct IntrinsicTypedArrayCtor : FunctionObject {
};
struct TypedArrayCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope, TypedArray::Type t);
+ void init(ExecutionEngine *engine, TypedArray::Type t);
TypedArray::Type type;
};
@@ -141,8 +141,6 @@ struct IntrinsicTypedArrayCtor: FunctionObject
{
V4_OBJECT2(IntrinsicTypedArrayCtor, FunctionObject)
- static constexpr VTable::Call virtualCall = nullptr;
-
static ReturnedValue method_of(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_from(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
diff --git a/src/qml/jsruntime/qv4urlobject.cpp b/src/qml/jsruntime/qv4urlobject.cpp
index 4ece91a2a2..89c8b9cda2 100644
--- a/src/qml/jsruntime/qv4urlobject.cpp
+++ b/src/qml/jsruntime/qv4urlobject.cpp
@@ -18,9 +18,9 @@ DEFINE_OBJECT_VTABLE(UrlSearchParamsObject);
DEFINE_OBJECT_VTABLE(UrlSearchParamsCtor);
-void Heap::UrlCtor::init(QV4::ExecutionContext *scope)
+void Heap::UrlCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QLatin1String("URL"));
+ Heap::FunctionObject::init(engine, QLatin1String("URL"));
}
void UrlPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -750,9 +750,9 @@ ReturnedValue UrlCtor::virtualCallAsConstructor(const FunctionObject *that, cons
}
-void Heap::UrlSearchParamsCtor::init(QV4::ExecutionContext *scope)
+void Heap::UrlSearchParamsCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QLatin1String("URLSearchParams"));
+ Heap::FunctionObject::init(engine, QLatin1String("URLSearchParams"));
}
void UrlSearchParamsPrototype::init(ExecutionEngine *engine, Object *ctor)
diff --git a/src/qml/jsruntime/qv4urlobject_p.h b/src/qml/jsruntime/qv4urlobject_p.h
index d45b74fcaa..b3b76e1158 100644
--- a/src/qml/jsruntime/qv4urlobject_p.h
+++ b/src/qml/jsruntime/qv4urlobject_p.h
@@ -47,7 +47,7 @@ DECLARE_HEAP_OBJECT(UrlObject, Object)
struct UrlCtor : FunctionObject
{
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
// clang-format off
@@ -66,7 +66,7 @@ DECLARE_HEAP_OBJECT(UrlSearchParamsObject, Object)
struct UrlSearchParamsCtor : FunctionObject
{
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index f2d01c56cd..eaa57a36aa 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -309,7 +309,10 @@ inline bool Value::isObject() const
inline bool Value::isFunctionObject() const
{
HeapBasePtr b = heapObject();
- return b && b->internalClass->vtable->isFunctionObject;
+ if (!b)
+ return false;
+ const VTable *vtable = b->internalClass->vtable;
+ return vtable->call || vtable->callAsConstructor;
}
inline bool Value::isPrimitive() const
diff --git a/src/qml/jsruntime/qv4vtable_p.h b/src/qml/jsruntime/qv4vtable_p.h
index 8ec8c87a31..0532fdc32d 100644
--- a/src/qml/jsruntime/qv4vtable_p.h
+++ b/src/qml/jsruntime/qv4vtable_p.h
@@ -64,7 +64,7 @@ struct VTable
quint8 isExecutionContext;
quint8 isString;
quint8 isObject;
- quint8 isFunctionObject;
+ quint8 isTailCallable;
quint8 isErrorObject;
quint8 isArrayData;
quint8 isStringOrSymbol;
@@ -110,20 +110,38 @@ template<class Class>
constexpr VTable::CallWithMetaTypes vtableMetaTypesCallEntry()
{
// If Class overrides virtualCallWithMetaTypes, return that.
- // Otherwise, if it overrides virtualCall, return nullptr so that we convert calls.
+ // Otherwise, if it overrides virtualCall, return convertAndCall.
// Otherwise, just return whatever the base class had.
- // A simple != is not considered constexpr, so we have to jump through some hoops.
- if constexpr (!std::is_same_v<
- VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
- VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>) {
- return Class::virtualCallWithMetaTypes;
- }
-
- if constexpr (!std::is_same_v<
- VTableCallWrapper<Class::virtualCall>,
- VTableCallWrapper<Class::SuperClass::virtualCall>>) {
- return nullptr;
+ // A simple == on methods is not considered constexpr, so we have to jump through some hoops.
+
+ static_assert(
+ std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>
+ || !std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<nullptr>>,
+ "You mustn't override virtualCallWithMetaTypes with nullptr");
+
+ static_assert(
+ std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualConvertAndCall>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualConvertAndCall>>
+ || !std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualConvertAndCall>,
+ VTableCallWithMetaTypesWrapper<nullptr>>,
+ "You mustn't override virtualConvertAndCall with nullptr");
+
+ if constexpr (
+ std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>
+ && !std::is_same_v<
+ VTableCallWrapper<Class::virtualCall>,
+ VTableCallWrapper<Class::SuperClass::virtualCall>>) {
+ // Converting from metatypes to JS signature is easy.
+ return Class::virtualConvertAndCall;
}
return Class::virtualCallWithMetaTypes;
@@ -133,21 +151,27 @@ template<class Class>
constexpr VTable::Call vtableJsTypesCallEntry()
{
// If Class overrides virtualCall, return that.
- // Otherwise, if it overrides virtualCallWithMetaTypes, return nullptr so that we convert calls.
+ // Otherwise, if it overrides virtualCallWithMetaTypes, fail.
+ // (We cannot determine the target types to call virtualCallWithMetaTypes in that case)
// Otherwise, just return whatever the base class had.
- // A simple != is not considered constexpr, so we have to jump through some hoops.
- if constexpr (!std::is_same_v<
- VTableCallWrapper<Class::virtualCall>,
- VTableCallWrapper<Class::SuperClass::virtualCall>>) {
- return Class::virtualCall;
- }
+ // A simple == on methods is not considered constexpr, so we have to jump through some hoops.
- if constexpr (!std::is_same_v<
- VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
- VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>) {
- return nullptr;
- }
+ static_assert(
+ !std::is_same_v<
+ VTableCallWrapper<Class::virtualCall>,
+ VTableCallWrapper<Class::SuperClass::virtualCall>>
+ || std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>,
+ "If you override virtualCallWithMetaTypes, override virtualCall, too");
+
+ static_assert(
+ std::is_same_v<
+ VTableCallWrapper<Class::virtualCall>,
+ VTableCallWrapper<Class::SuperClass::virtualCall>>
+ || VTableCallWrapper<Class::virtualCall>::c != nullptr,
+ "You mustn't override virtualCall with nullptr");
return Class::virtualCall;
}
@@ -174,6 +198,7 @@ protected:
static constexpr VTable::Call virtualCall = nullptr;
static constexpr VTable::CallAsConstructor virtualCallAsConstructor = nullptr;
static constexpr VTable::CallWithMetaTypes virtualCallWithMetaTypes = nullptr;
+ static constexpr VTable::CallWithMetaTypes virtualConvertAndCall = nullptr;
static constexpr VTable::ResolveLookupGetter virtualResolveLookupGetter = nullptr;
static constexpr VTable::ResolveLookupSetter virtualResolveLookupSetter = nullptr;
@@ -196,7 +221,7 @@ protected:
classname::IsExecutionContext, \
classname::IsString, \
classname::IsObject, \
- classname::IsFunctionObject, \
+ classname::IsTailCallable, \
classname::IsErrorObject, \
classname::IsArrayData, \
classname::IsStringOrSymbol, \
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 57954d7d1a..32b609f5ff 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -3399,6 +3399,7 @@ BindingProperty: PropertyName T_COLON BindingIdentifier InitializerOpt_In;
case $rule_number: {
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, stringRef(3), sym(4).Expression);
node->colonToken = loc(2);
+ node->identifierToken = loc(3);
sym(1).Node = node;
} break;
./
@@ -3567,6 +3568,11 @@ IterationStatement: T_FOR T_LPAREN LexicalDeclaration T_SEMICOLON ExpressionOpt_
AST::ForStatement *node = new (pool) AST::ForStatement(
static_cast<AST::VariableStatement *>(sym(3).Node)->declarations, sym(5).Expression,
sym(7).Expression, sym(9).Statement);
+ if (node->declarations) {
+ AST::PatternElement *pe = node->declarations->declaration;
+ pe->isForDeclaration = true;
+ pe->declarationKindToken = loc(3);
+ }
node->forToken = loc(1);
node->lparenToken = loc(2);
node->firstSemicolonToken = loc(4);
@@ -3638,6 +3644,7 @@ ForDeclaration: Var BindingIdentifier TypeAnnotationOpt;
node->identifierToken = loc(2);
node->scope = sym(1).scope;
node->isForDeclaration = true;
+ node->declarationKindToken = loc(1);
sym(1).Node = node;
} break;
./
@@ -3650,6 +3657,7 @@ ForDeclaration: Var BindingPattern;
auto *node = new (pool) AST::PatternElement(sym(2).Pattern, nullptr);
node->scope = sym(1).scope;
node->isForDeclaration = true;
+ node->declarationKindToken = loc(1);
sym(1).Node = node;
} break;
./
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index 2bb9b3f001..bfeab7518c 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -995,6 +995,7 @@ public:
Type type = Literal;
TypeAnnotation *typeAnnotation = nullptr;
// when used in a VariableDeclarationList
+ SourceLocation declarationKindToken;
VariableScope scope = VariableScope::NoScope;
bool isForDeclaration = false;
bool isInjectedSignalParameter = false;
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index 704c7eb00d..d57fb7c54a 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -1007,7 +1007,7 @@ again:
int Lexer::scanString(ScanStringMode mode)
{
- QChar quote = (mode == TemplateContinuation) ? QChar(TemplateHead) : QChar(mode);
+ const char16_t quote = mode == TemplateContinuation ? TemplateHead : mode;
// we actually use T_STRING_LITERAL also for multiline strings, should we want to
// change that we should set it to:
// _state.tokenKind == T_PARTIAL_SINGLE_QUOTE_STRING_LITERAL ||
@@ -1214,6 +1214,32 @@ int Lexer::scanString(ScanStringMode mode)
int Lexer::scanNumber(QChar ch)
{
+ auto scanOptionalNumericSeparator = [this](auto isNextCharacterValid){
+ if (_state.currentChar == u'_') {
+ if (peekChar() == u'_') {
+ _state.errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser",
+ "There can be at most one numeric separator beetwen digits"
+ );
+ return false;
+ }
+
+ if (!isNextCharacterValid()) {
+ _state.errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser",
+ "A trailing numeric separator is not allowed in numeric literals"
+ );
+ return false;
+ }
+
+ scanChar();
+ }
+
+ return true;
+ };
+
if (ch == u'0') {
if (_state.currentChar == u'x' || _state.currentChar == u'X') {
ch = _state.currentChar; // remember the x or X to use it in the error message below.
@@ -1238,6 +1264,9 @@ int Lexer::scanNumber(QChar ch)
d *= 16;
d += digit;
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){ return isHexDigit(peekChar()); }))
+ return T_ERROR;
}
_state.tokenValue = d;
@@ -1265,6 +1294,12 @@ int Lexer::scanNumber(QChar ch)
d *= 8;
d += digit;
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){
+ return isOctalDigit(peekChar().unicode());
+ })) {
+ return T_ERROR;
+ }
}
_state.tokenValue = d;
@@ -1294,6 +1329,12 @@ int Lexer::scanNumber(QChar ch)
d *= 2;
d += digit;
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){
+ return peekChar().unicode() == u'0' || peekChar().unicode() == u'1';
+ })) {
+ return T_ERROR;
+ }
}
_state.tokenValue = d;
@@ -1311,9 +1352,15 @@ int Lexer::scanNumber(QChar ch)
chars.append(ch.unicode());
if (ch != u'.') {
+ if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); }))
+ return T_ERROR;
+
while (_state.currentChar.isDigit()) {
chars.append(_state.currentChar.unicode());
scanChar(); // consume the digit
+
+ if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); }))
+ return T_ERROR;
}
if (_state.currentChar == u'.') {
@@ -1325,6 +1372,9 @@ int Lexer::scanNumber(QChar ch)
while (_state.currentChar.isDigit()) {
chars.append(_state.currentChar.unicode());
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); }))
+ return T_ERROR;
}
if (_state.currentChar == u'e' || _state.currentChar == u'E') {
@@ -1342,6 +1392,9 @@ int Lexer::scanNumber(QChar ch)
while (_state.currentChar.isDigit()) {
chars.append(_state.currentChar.unicode());
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); }))
+ return T_ERROR;
}
}
}
diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h
index b6144e8894..d991bcff58 100644
--- a/src/qml/parser/qqmljslexer_p.h
+++ b/src/qml/parser/qqmljslexer_p.h
@@ -240,7 +240,7 @@ private:
int scanToken();
int scanNumber(QChar ch);
int scanVersionNumber(QChar ch);
- enum ScanStringMode {
+ enum ScanStringMode : char16_t {
SingleQuote = '\'',
DoubleQuote = '"',
TemplateHead = '`',
diff --git a/src/qml/qml/ftw/qqmlnullablevalue_p.h b/src/qml/qml/ftw/qqmlnullablevalue_p.h
index 9a3f032b68..62899e4644 100644
--- a/src/qml/qml/ftw/qqmlnullablevalue_p.h
+++ b/src/qml/qml/ftw/qqmlnullablevalue_p.h
@@ -30,7 +30,7 @@ struct QQmlNullableValue
{}
QQmlNullableValue(QQmlNullableValue<T> &&o) noexcept
- : m_value(std::move(o.value))
+ : m_value(std::move(o.m_value))
, m_isNull(std::exchange(o.m_isNull, true))
{}
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index eb716671b1..63e67ac804 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -10,7 +10,7 @@
#include <private/qqmlcomponent_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlfinalizer_p.h>
-#include <private/qqmlloggingcategory_p.h>
+#include <private/qqmlloggingcategorybase_p.h>
#include <private/qqmlmetatype_p.h>
#include <private/qqmlmetatypedata_p.h>
#include <private/qqmltype_p_p.h>
@@ -1677,10 +1677,10 @@ const QLoggingCategory *AOTCompiledContext::resolveLoggingCategory(QObject *wrap
{
if (wrapper) {
// We have to check this here because you may pass a plain QObject that only
- // turns out to be a QQmlLoggingCategory at run time.
- if (QQmlLoggingCategory *qQmlLoggingCategory
- = qobject_cast<QQmlLoggingCategory *>(wrapper)) {
- QLoggingCategory *loggingCategory = qQmlLoggingCategory->category();
+ // turns out to be a QQmlLoggingCategoryBase at run time.
+ if (QQmlLoggingCategoryBase *qQmlLoggingCategory
+ = qobject_cast<QQmlLoggingCategoryBase *>(wrapper)) {
+ const QLoggingCategory *loggingCategory = qQmlLoggingCategory->category();
*ok = true;
if (!loggingCategory) {
engine->handle()->throwError(
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 47f8e5c429..4dfee0a3c6 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -533,7 +533,8 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
delayedError()->setErrorDescription(QLatin1String("Unable to assign [undefined] to ")
+ typeName);
return false;
- } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>()) {
+ } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
+ f && !f->as<QV4::QQmlTypeWrapper>()) {
if (f->isBinding())
delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
else
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 3f9ce26764..0bac2f45a2 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -62,7 +62,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int
function += QLatin1String(") { ") + expression + QLatin1String(" })");
QV4::Scope valueScope(v4);
- QV4::ScopedFunctionObject f(valueScope, evalFunction(context(), scopeObject(), function, fileName, line));
+ QV4::Scoped<QV4::JavaScriptFunctionObject> f(
+ valueScope, evalFunction(context(), scopeObject(), function, fileName, line));
QV4::ScopedContext context(valueScope, f->scope());
setupFunction(context, f->function());
}
@@ -107,7 +108,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int
// we need to run the outer function to get the nested one.
if (function->isClosureWrapper()) {
bool isUndefined = false;
- QV4::ScopedFunctionObject result(
+ QV4::Scoped<QV4::JavaScriptFunctionObject> result(
valueScope, QQmlJavaScriptExpression::evaluate(&isUndefined));
Q_ASSERT(!isUndefined);
diff --git a/src/qml/qml/qqmlbuiltinfunctions.cpp b/src/qml/qml/qqmlbuiltinfunctions.cpp
index 5c6daa0969..b736cb2f4c 100644
--- a/src/qml/qml/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/qqmlbuiltinfunctions.cpp
@@ -3,48 +3,35 @@
#include "qqmlbuiltinfunctions_p.h"
-#include <QtQml/qqmlcomponent.h>
-#include <QtQml/qqmlfile.h>
-#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
-#include <private/qqmlloggingcategory_p.h>
-#include <private/qqmlstringconverters_p.h>
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
-#endif
-#include <private/qqmldelayedcallqueue_p.h>
-#include <QFileInfo>
-
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
-#include <private/qqmlglobal_p.h>
-
+#include <private/qqmldelayedcallqueue_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlloggingcategorybase_p.h>
#include <private/qqmlplatform_p.h>
+#include <private/qqmlstringconverters_p.h>
+#include <private/qv4dateobject_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4include_p.h>
-#include <private/qv4context_p.h>
-#include <private/qv4stringobject_p.h>
-#include <private/qv4dateobject_p.h>
#include <private/qv4mm_p.h>
-#include <private/qv4jsonobject_p.h>
-#include <private/qv4objectproto_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4stackframe_p.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qdatetime.h>
+#include <QtQml/qqmlfile.h>
+
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qcryptographichash.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qpoint.h>
#include <QtCore/qrect.h>
#include <QtCore/qsize.h>
-#include <QtCore/qpoint.h>
+#include <QtCore/qstring.h>
#include <QtCore/qurl.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qloggingcategory.h>
-
-#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -172,6 +159,7 @@ The following functions are also on the Qt object.
\li \c "android" - Android
\li \c "ios" - iOS
\li \c "tvos" - tvOS
+ \li \c "visionos" - visionOS
\li \c "linux" - Linux
\li \c "osx" - \macos
\li \c "qnx" - QNX (since Qt 5.9.3)
@@ -180,6 +168,9 @@ The following functions are also on the Qt object.
\li \c "wasm" - WebAssembly
\endlist
+ \note The property's value on \macos is "osx", regardless of Apple naming convention.
+ The returned value will be updated to "macos" for Qt 7.
+
\row
\li \c platform.pluginName
\li This is the name of the platform set on the QGuiApplication instance
@@ -262,6 +253,9 @@ The \c status property will be updated as the operation progresses.
If provided, \a callback is invoked when the operation completes. The callback is passed
the same object as is returned from the Qt.include() call.
+
+\warning Using this function is strict mode does not actually put identifier into the
+current context.
*/
// Qt.include() is implemented in qv4include.cpp
@@ -1469,11 +1463,12 @@ use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}.
*/
/*!
+\since 6.5
\qmlmethod Component Qt::createComponent(string moduleUri, string typeName, enumeration mode, QtObject parent)
\overload
Returns a \l Component object created for the type specified by \a moduleUri and \a typeName.
\qml
-import QtQuick
+import QtQml
QtObject {
id: root
property Component myComponent: Qt.createComponent("QtQuick", "Rectangle", Component.Asynchronous, root)
@@ -1613,14 +1608,21 @@ QLocale QtObject::locale(const QString &name) const
}
#endif
-void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *bindingFunction)
+void Heap::QQmlBindingFunction::init(const QV4::JavaScriptFunctionObject *bindingFunction)
{
Scope scope(bindingFunction->engine());
ScopedContext context(scope, bindingFunction->scope());
- FunctionObject::init(context, bindingFunction->function());
+ JavaScriptFunctionObject::init(context, bindingFunction->function());
this->bindingFunction.set(internalClass->engine, bindingFunction->d());
}
+ReturnedValue QQmlBindingFunction::virtualCall(
+ const FunctionObject *f, const Value *, const Value *, int)
+{
+ // Mark this as a callable object, so that we can perform the binding magic on it.
+ return f->engine()->throwTypeError(QStringLiteral("Bindings must not be called directly."));
+}
+
QQmlSourceLocation QQmlBindingFunction::currentLocation() const
{
QV4::CppStackFrame *frame = engine()->currentStackFrame;
@@ -1675,7 +1677,8 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction);
*/
QJSValue QtObject::binding(const QJSValue &function) const
{
- const QV4::FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(&function);
+ const QV4::JavaScriptFunctionObject *f
+ = QJSValuePrivate::asManagedType<JavaScriptFunctionObject>(&function);
QV4::ExecutionEngine *e = v4Engine();
if (!f) {
return QJSValuePrivate::fromReturnedValue(
@@ -1813,7 +1816,8 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *argv,
int start = 0;
if (argc > 0) {
if (const QObjectWrapper* wrapper = argv[0].as<QObjectWrapper>()) {
- if (QQmlLoggingCategory* category = qobject_cast<QQmlLoggingCategory*>(wrapper->object())) {
+ if (QQmlLoggingCategoryBase *category
+ = qobject_cast<QQmlLoggingCategoryBase *>(wrapper->object())) {
if (category->category())
loggingCategory = category->category();
else
@@ -2138,7 +2142,7 @@ ReturnedValue GlobalExtensions::method_qsTranslate(const FunctionObject *b, cons
}
/*!
- \qmlmethod string Qt::qsTranslateNoOp(string context, string sourceText, string disambiguation)
+ \qmlmethod string Qt::QT_TRANSLATE_NOOP(string context, string sourceText, string disambiguation)
Marks \a sourceText for dynamic translation in the given \a context; i.e, the stored \a sourceText
will not be altered.
@@ -2253,7 +2257,7 @@ ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value
}
/*!
- \qmlmethod string Qt::qsTrNoOp(string sourceText, string disambiguation)
+ \qmlmethod string Qt::QT_TR_NOOP(string sourceText, string disambiguation)
Marks \a sourceText for dynamic translation; i.e, the stored \a sourceText
will not be altered.
@@ -2334,7 +2338,7 @@ ReturnedValue GlobalExtensions::method_qsTrId(const FunctionObject *b, const Val
}
/*!
- \qmlmethod string Qt::qsTrIdNoOp(string id)
+ \qmlmethod string Qt::QT_TRID_NOOP(string id)
Marks \a id for dynamic translation.
diff --git a/src/qml/qml/qqmlbuiltinfunctions_p.h b/src/qml/qml/qqmlbuiltinfunctions_p.h
index 9ceedad28b..c2732e1aff 100644
--- a/src/qml/qml/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/qqmlbuiltinfunctions_p.h
@@ -46,7 +46,6 @@ class Q_QML_EXPORT QtObject : public QObject
QML_NAMED_ELEMENT(Qt)
QML_SINGLETON
QML_EXTENDED_NAMESPACE(Qt)
- QML_ADDED_IN_VERSION(2, 0)
Q_CLASSINFO("QML.StrictArguments", "true")
@@ -199,10 +198,10 @@ struct ConsoleObject : Object {
};
#define QQmlBindingFunctionMembers(class, Member) \
- Member(class, Pointer, FunctionObject *, bindingFunction)
-DECLARE_HEAP_OBJECT(QQmlBindingFunction, FunctionObject) {
+ Member(class, Pointer, JavaScriptFunctionObject *, bindingFunction)
+DECLARE_HEAP_OBJECT(QQmlBindingFunction, JavaScriptFunctionObject) {
DECLARE_MARKOBJECTS(QQmlBindingFunction)
- void init(const QV4::FunctionObject *bindingFunction);
+ void init(const QV4::JavaScriptFunctionObject *bindingFunction);
};
}
@@ -245,11 +244,14 @@ struct Q_QML_EXPORT GlobalExtensions {
};
-struct QQmlBindingFunction : public QV4::FunctionObject
+struct QQmlBindingFunction : public QV4::JavaScriptFunctionObject
{
- V4_OBJECT2(QQmlBindingFunction, FunctionObject)
+ V4_OBJECT2(QQmlBindingFunction, JavaScriptFunctionObject)
- Heap::FunctionObject *bindingFunction() const { return d()->bindingFunction; }
+ static ReturnedValue virtualCall(
+ const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+
+ Heap::JavaScriptFunctionObject *bindingFunction() const { return d()->bindingFunction; }
QQmlSourceLocation currentLocation() const; // from caller stack trace
};
diff --git a/src/qml/qml/qqmlcontextdata_p.h b/src/qml/qml/qqmlcontextdata_p.h
index c8e362ec8d..3aeabf72fa 100644
--- a/src/qml/qml/qqmlcontextdata_p.h
+++ b/src/qml/qml/qqmlcontextdata_p.h
@@ -292,6 +292,10 @@ public:
return m_typeCompilationUnit && m_typeCompilationUnit->valueTypesAreAddressable();
}
+ bool valueTypesAreAssertable() const {
+ return m_typeCompilationUnit && m_typeCompilationUnit->valueTypesAreAssertable();
+ }
+
private:
friend class QQmlGuardedContextData;
friend class QQmlContextPrivate;
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
index efd8519a58..ead8a717f5 100644
--- a/src/qml/qml/qqmldelayedcallqueue.cpp
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -126,8 +126,9 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::Executi
// if it's a qobject function wrapper, guard against qobject deletion
dfc.m_objectGuard = QQmlGuard<QObject>(functionData.first);
dfc.m_guarded = true;
- } else if (func->scope()->type == QV4::Heap::ExecutionContext::Type_QmlContext) {
- QV4::QmlContext::Data *g = static_cast<QV4::QmlContext::Data *>(func->scope());
+ } else if (const auto *js = func->as<QV4::JavaScriptFunctionObject>();
+ js && js->scope()->type == QV4::Heap::ExecutionContext::Type_QmlContext) {
+ QV4::QmlContext::Data *g = static_cast<QV4::QmlContext::Data *>(js->scope());
Q_ASSERT(g->qml()->scopeObject);
dfc.m_objectGuard = QQmlGuard<QObject>(g->qml()->scopeObject);
dfc.m_guarded = true;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index c7812059a1..593fce3371 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -4,57 +4,44 @@
#include "qqmlengine_p.h"
#include "qqmlengine.h"
-#include "qqmlcontext_p.h"
-#include "qqml.h"
-#include "qqmlcontext.h"
-#include "qqmlscriptstring.h"
-#include "qqmlglobal_p.h"
-#include "qqmlnotifier_p.h"
-#include "qqmlincubator.h"
-#include "qqmlabstracturlinterceptor.h"
-
-#include <private/qqmldirparser_p.h>
+#include <private/qqmlabstractbinding_p.h>
#include <private/qqmlboundsignal_p.h>
-#include <private/qqmljsdiagnosticmessage_p.h>
-#include <private/qqmltype_p_p.h>
+#include <private/qqmlcontext_p.h>
+#include <private/qqmlnotifier_p.h>
#include <private/qqmlpluginimporter_p.h>
-#include <QtCore/qstandardpaths.h>
-#include <QtCore/qmetaobject.h>
-#include <QDebug>
+#include <private/qqmlprofiler_p.h>
+#include <private/qqmlscriptdata_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qqmltype_p.h>
+#include <private/qqmltypedata_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+
+#include <private/qobject_p.h>
+#include <private/qthread_p.h>
+
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlincubator.h>
+#include <QtQml/qqmlscriptstring.h>
+
#include <QtCore/qcoreapplication.h>
#include <QtCore/qcryptographichash.h>
#include <QtCore/qdir.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qstandardpaths.h>
#include <QtCore/qthread.h>
-#include <private/qthread_p.h>
-#include <private/qqmlscriptdata_p.h>
-#include <QtQml/private/qqmlcomponentattached_p.h>
-#include <QtQml/private/qqmlsourcecoordinate_p.h>
-#include <QtQml/private/qqmlcomponent_p.h>
#if QT_CONFIG(qml_network)
-#include "qqmlnetworkaccessmanagerfactory.h"
-#include <QNetworkAccessManager>
-#endif
-
-#include <private/qobject_p.h>
-#include <private/qmetaobject_p.h>
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
-#endif
-#include <private/qqmlbind_p.h>
-#include <private/qqmlconnections_p.h>
-#if QT_CONFIG(qml_animation)
-#include <private/qqmltimer_p.h>
+#include <QtQml/qqmlnetworkaccessmanagerfactory.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
#endif
-#include <private/qqmlplatform_p.h>
-#include <private/qqmlloggingcategory_p.h>
-#include <private/qv4sequenceobject_p.h>
#ifdef Q_OS_WIN // for %APPDATA%
# include <qt_windows.h>
# include <shlobj.h>
-# include <qlibrary.h>
+# include <QtCore/qlibrary.h>
# ifndef CSIDL_APPDATA
# define CSIDL_APPDATA 0x001a // <username>\Application Data
# endif
@@ -1945,7 +1932,7 @@ void QQmlEnginePrivate::executeRuntimeFunction(const QV4::ExecutableCompilationU
// different version of ExecutionEngine::callInContext() that returns a
// QV4::ReturnedValue with no arguments since they are not needed by the
// outer function anyhow
- QV4::ScopedFunctionObject result(scope,
+ QV4::Scoped<QV4::JavaScriptFunctionObject> result(scope,
v4->callInContext(function, thisObject, callContext, 0, nullptr));
Q_ASSERT(result->function());
Q_ASSERT(result->function()->compilationUnit == function->compilationUnit);
@@ -2042,7 +2029,7 @@ static inline QString shellNormalizeFileName(const QString &name)
bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
{
-#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
+#if defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
QFileInfo info(fileName);
const QString absolute = info.absoluteFilePath();
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index 1273067187..2e3fa5f86c 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -415,6 +415,10 @@ static QVariant byProperties(
if (source.metaType() == QMetaType::fromType<QJSValue>()) {
QJSValue val = source.value<QJSValue>();
+ // Generally, the GC might collect a Value at any point so that
+ // a `ScopedValue` should be used.
+ // In this case, the Value is tied to a `QJSValue` which is
+ // persistent to the GC and thus the cast is safe.
return byProperties(
targetMetaObject, targetMetaType, QV4::Value(QJSValuePrivate::asReturnedValue(&val)));
}
@@ -560,6 +564,10 @@ bool QQmlValueTypeProvider::populateValueType(
{
if (sourceMetaType == QMetaType::fromType<QJSValue>()) {
const QJSValue *val = static_cast<const QJSValue *>(source);
+ // Generally, the GC might collect a Value at any point so that
+ // a `ScopedValue` should be used.
+ // In this case, the Value is tied to a `QJSValue` which is
+ // persistent to the GC and thus the cast is safe.
return populateValueType(
targetMetaType, target, QV4::Value(QJSValuePrivate::asReturnedValue(val)));
}
diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
index 98fe2e6a79..5aa2f3ee6f 100644
--- a/src/qml/qml/qqmlglobal_p.h
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -270,7 +270,6 @@ class Q_QML_EXPORT QQmlApplication : public QObject
Q_PROPERTY(QString organization READ organization WRITE setOrganization NOTIFY organizationChanged)
Q_PROPERTY(QString domain READ domain WRITE setDomain NOTIFY domainChanged)
QML_ANONYMOUS
- QML_ADDED_IN_VERSION(2, 0)
public:
QQmlApplication(QObject* parent=nullptr);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 86380294ba..217cb44669 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1516,8 +1516,9 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
// 6. $QML_IMPORT_PATH
// 7. QLibraryInfo::QmlImportsPath
- QString installImportsPath = QLibraryInfo::path(QLibraryInfo::QmlImportsPath);
- addImportPath(installImportsPath);
+ const auto paths = QLibraryInfo::paths(QLibraryInfo::QmlImportsPath);
+ for (const auto &installImportsPath: paths)
+ addImportPath(installImportsPath);
auto addEnvImportPath = [this](const char *var) {
if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(var))) {
diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp
index b29ce185ef..e1019b804f 100644
--- a/src/qml/qml/qqmlirloader.cpp
+++ b/src/qml/qml/qqmlirloader.cpp
@@ -85,6 +85,8 @@ void QQmlIRLoader::load()
valueTypeBehavior |= Pragma::Copy;
if (unit->flags & QV4::CompiledData::Unit::ValueTypesAddressable)
valueTypeBehavior |= Pragma::Addressable;
+ if (unit->flags & QV4::CompiledData::Unit::ValueTypesAssertable)
+ valueTypeBehavior |= Pragma::Assertable;
if (valueTypeBehavior)
createValueTypePragma(Pragma::ValueTypeBehavior, valueTypeBehavior);
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index 5d26bf8a68..82c65ccf82 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -54,13 +54,14 @@ private:
static QV4::ReturnedValue method_toLocaleCurrencyString(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
};
-
-namespace QQmlLocale
+// This needs to be a struct so that we can derive from QLocale and inherit its enums. Then we can
+// use it as extension in QQmlLocaleEnums and expose all the enums in one go, without duplicating
+// any in different qmltypes files.
+struct Q_QML_EXPORT QQmlLocale : public QLocale
{
- Q_NAMESPACE_EXPORT(Q_QML_EXPORT)
- QML_NAMED_ELEMENT(Locale)
- QML_ADDED_IN_VERSION(2, 2)
- QML_NAMESPACE_EXTENDED(QLocale)
+ Q_GADGET
+ QML_ANONYMOUS
+public:
// Qt defines Sunday as 7, but JS Date assigns Sunday 0
enum DayOfWeek {
@@ -72,11 +73,13 @@ namespace QQmlLocale
Friday = Qt::Friday,
Saturday = Qt::Saturday
};
- Q_ENUM_NS(DayOfWeek)
+ Q_ENUM(DayOfWeek)
- Q_QML_EXPORT QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName);
- Q_QML_EXPORT void registerStringLocaleCompare(QV4::ExecutionEngine *engine);
- Q_QML_EXPORT QV4::ReturnedValue method_localeCompare(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName);
+ static void registerStringLocaleCompare(QV4::ExecutionEngine *engine);
+ static QV4::ReturnedValue method_localeCompare(
+ const QV4::FunctionObject *, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc);
};
struct DayOfWeekList
diff --git a/src/qml/qml/qqmlloggingcategorybase_p.h b/src/qml/qml/qqmlloggingcategorybase_p.h
new file mode 100644
index 0000000000..4a3c4cf6aa
--- /dev/null
+++ b/src/qml/qml/qqmlloggingcategorybase_p.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLLOGGINGCATEGORYBASE_P_H
+#define QQMLLOGGINGCATEGORYBASE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qqml.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qloggingcategory.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_EXPORT QQmlLoggingCategoryBase : public QObject
+{
+ Q_OBJECT
+ QML_ANONYMOUS
+
+public:
+ QQmlLoggingCategoryBase(QObject *parent = nullptr) : QObject(parent) {}
+
+ const QLoggingCategory *category() const { return m_category.get(); }
+ void setCategory(const char *name, QtMsgType type)
+ {
+ m_category = std::make_unique<QLoggingCategory>(name, type);
+ }
+
+private:
+ std::unique_ptr<QLoggingCategory> m_category;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLLOGGINGCATEGORYBASE_P_H
diff --git a/src/qml/qml/qqmlmetamoduleregistration.cpp b/src/qml/qml/qqmlmetamoduleregistration.cpp
deleted file mode 100644
index 8e55b62b3a..0000000000
--- a/src/qml/qml/qqmlmetamoduleregistration.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include <private/qtqmlglobal_p.h>
-#include <qqmlmoduleregistration.h>
-#include <qqml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Provide the type registration for QtQml here, in libQtQml.so.
-// This way we get a completely functional QtQml module and don't have to
-// rely on the plugin to be loaded.
-// In CMakeLists.txt we've specified NO_GENERATE_QMLTYPES to prevent
-// the generation of an extra type registration file.
-Q_QML_EXPORT void qml_register_types_QtQml()
-{
- // ### Qt7: Handle version 6 like version 2.
- qmlRegisterModule("QtQml", 2, 0);
- qmlRegisterModule("QtQml", 2, 254);
- qmlRegisterModule("QtQml", QT_VERSION_MAJOR, 0);
- qmlRegisterModule("QtQml", QT_VERSION_MAJOR, QT_VERSION_MINOR);
-}
-
-static const QQmlModuleRegistration registration("QtQml", qml_register_types_QtQml);
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp
index dbd54b5f11..dd52ee2090 100644
--- a/src/qml/qml/qqmlplatform.cpp
+++ b/src/qml/qml/qqmlplatform.cpp
@@ -22,13 +22,18 @@ QQmlPlatform::~QQmlPlatform()
QString QQmlPlatform::os()
{
+ // ### Qt7: Consider implementing in terms of QSysInfo
+
#if defined(Q_OS_ANDROID)
return QStringLiteral("android");
#elif defined(Q_OS_IOS)
return QStringLiteral("ios");
#elif defined(Q_OS_TVOS)
return QStringLiteral("tvos");
-#elif defined(Q_OS_MAC)
+#elif defined(Q_OS_VISIONOS)
+ return QStringLiteral("visionos");
+#elif defined(Q_OS_MACOS)
+ // ### Qt7: Replace with "macos"
return QStringLiteral("osx");
#elif defined(Q_OS_WIN)
return QStringLiteral("windows");
diff --git a/src/qml/qml/qqmlplatform_p.h b/src/qml/qml/qqmlplatform_p.h
index b8d2167fd5..9905f6330c 100644
--- a/src/qml/qml/qqmlplatform_p.h
+++ b/src/qml/qml/qqmlplatform_p.h
@@ -27,7 +27,6 @@ class Q_QML_EXPORT QQmlPlatform : public QObject
Q_PROPERTY(QString os READ os CONSTANT)
Q_PROPERTY(QString pluginName READ pluginName CONSTANT)
QML_ANONYMOUS
- QML_ADDED_IN_VERSION(2, 0)
public:
explicit QQmlPlatform(QObject *parent = nullptr);
diff --git a/src/qml/qml/qqmlproperty.h b/src/qml/qml/qqmlproperty.h
index 0878034bab..cbe5eb21ad 100644
--- a/src/qml/qml/qqmlproperty.h
+++ b/src/qml/qml/qqmlproperty.h
@@ -23,7 +23,6 @@ class Q_QML_EXPORT QQmlProperty
{
Q_GADGET
QML_ANONYMOUS
- QML_ADDED_IN_VERSION(2, 15)
Q_PROPERTY(QObject *object READ object CONSTANT FINAL)
Q_PROPERTY(QString name READ name CONSTANT FINAL)
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index a225f94a3f..805113ad97 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -95,7 +95,6 @@ void QQmlPropertyData::load(const QMetaMethod &m)
case QMetaMethod::Constructor:
m_flags.setIsSignal(false);
m_flags.setIsConstructor(true);
- setPropType(QMetaType::fromType<QObject *>());
break;
default:
m_flags.setIsSignal(false);
@@ -687,28 +686,9 @@ const QQmlPropertyData *QQmlPropertyCache::findProperty(
return nullptr;
}
-QString QQmlPropertyData::name(QObject *object) const
-{
- if (!object)
- return QString();
-
- return name(object->metaObject());
-}
-QString QQmlPropertyData::name(const QMetaObject *metaObject) const
-{
- if (!metaObject || coreIndex() == -1)
- return QString();
- if (isFunction()) {
- QMetaMethod m = metaObject->method(coreIndex());
- return QString::fromUtf8(m.name().constData());
- } else {
- QMetaProperty p = metaObject->property(coreIndex());
- return QString::fromUtf8(p.name());
- }
-}
bool QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
{
diff --git a/src/qml/qml/qqmlpropertydata_p.h b/src/qml/qml/qqmlpropertydata_p.h
index 0fa7984f05..bdfa41ab7a 100644
--- a/src/qml/qml/qqmlpropertydata_p.h
+++ b/src/qml/qml/qqmlpropertydata_p.h
@@ -338,8 +338,17 @@ public:
static Flags flagsForProperty(const QMetaProperty &);
void load(const QMetaProperty &);
void load(const QMetaMethod &);
- QString name(QObject *) const;
- QString name(const QMetaObject *) const;
+
+ QString name(QObject *object) const { return object ? name(object->metaObject()) : QString(); }
+ QString name(const QMetaObject *metaObject) const
+ {
+ if (!metaObject || m_coreIndex == -1)
+ return QString();
+
+ return QString::fromUtf8(isFunction()
+ ? metaObject->method(m_coreIndex).name().constData()
+ : metaObject->property(m_coreIndex).name());
+ }
bool markAsOverrideOf(QQmlPropertyData *predecessor);
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 0d8786a9df..2ab81102c7 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -3,63 +3,122 @@
#include "qqmltypewrapper_p.h"
-#include <private/qqmlengine_p.h>
+#include <private/qjsvalue_p.h>
+
#include <private/qqmlcontext_p.h>
+#include <private/qqmlengine_p.h>
#include <private/qqmlmetaobject_p.h>
#include <private/qqmltypedata_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
-#include <private/qjsvalue_p.h>
-#include <private/qv4functionobject_p.h>
-#include <private/qv4objectproto_p.h>
-#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4identifiertable_p.h>
#include <private/qv4lookup_p.h>
+#include <private/qv4objectproto_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4symbol_p.h>
QT_BEGIN_NAMESPACE
using namespace QV4;
DEFINE_OBJECT_VTABLE(QQmlTypeWrapper);
+DEFINE_OBJECT_VTABLE(QQmlTypeConstructor);
DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper);
void Heap::QQmlTypeWrapper::init(TypeNameMode m, QObject *o, const QQmlTypePrivate *type)
{
Q_ASSERT(type);
- Object::init();
- mode = m;
+ FunctionObject::init();
+ flags = quint8(m) | quint8(Type);
object.init(o);
- typePrivate = type;
- QQmlType::refHandle(typePrivate);
+ QQmlType::refHandle(type);
+ t.typePrivate = type;
}
void Heap::QQmlTypeWrapper::init(
TypeNameMode m, QObject *o, QQmlTypeNameCache *type, const QQmlImportRef *import)
{
Q_ASSERT(type);
- Object::init();
- mode = m;
+ FunctionObject::init();
+ flags = quint8(m) | quint8(Namespace);
object.init(o);
- typeNamespace = type;
- typeNamespace->addref();
- importNamespace = import;
+ n.typeNamespace = type;
+ n.typeNamespace->addref();
+ n.importNamespace = import;
}
void Heap::QQmlTypeWrapper::destroy()
{
- Q_ASSERT(typePrivate || typeNamespace);
- QQmlType::derefHandle(typePrivate);
- typePrivate = nullptr;
- if (typeNamespace)
- typeNamespace->release();
+ switch (kind()) {
+ case Type:
+ Q_ASSERT(t.typePrivate);
+ QQmlType::derefHandle(t.typePrivate);
+ delete[] t.constructors;
+ break;
+ case Namespace:
+ Q_ASSERT(n.typeNamespace);
+ n.typeNamespace->release();
+ break;
+ }
+
object.destroy();
- Object::destroy();
+ FunctionObject::destroy();
}
QQmlType Heap::QQmlTypeWrapper::type() const
{
- return QQmlType(typePrivate);
+ switch (kind()) {
+ case Type:
+ return QQmlType(t.typePrivate);
+ case Namespace:
+ return QQmlType();
+ }
+
+ Q_UNREACHABLE_RETURN(QQmlType());
+}
+
+QQmlTypeNameCache::Result Heap::QQmlTypeWrapper::queryNamespace(
+ const QV4::String *name, QQmlEnginePrivate *enginePrivate) const
+{
+ Q_ASSERT(kind() == Namespace);
+ Q_ASSERT(n.typeNamespace);
+ Q_ASSERT(n.importNamespace);
+ return n.typeNamespace->query(name, n.importNamespace, QQmlTypeLoader::get(enginePrivate));
+
+}
+
+template<typename Callback>
+void warnWithLocation(const Heap::QQmlTypeWrapper *wrapper, Callback &&callback)
+{
+ auto log = qWarning().noquote().nospace();
+ if (const CppStackFrame *frame = wrapper->internalClass->engine->currentStackFrame)
+ log << frame->source() << ':' << frame->lineNumber() << ':';
+ callback(log.space());
+}
+
+void Heap::QQmlTypeWrapper::warnIfUncreatable() const
+{
+ const QQmlType t = type();
+ Q_ASSERT(t.isValid());
+
+ if (t.isValueType())
+ return;
+
+ if (t.isSingleton()) {
+ warnWithLocation(this, [&](QDebug &log) {
+ log << "You are calling a Q_INVOKABLE constructor of" << t.typeName()
+ << "which is a singleton in QML.";
+ });
+ return;
+ }
+
+ if (!t.isCreatable()) {
+ warnWithLocation(this, [&](QDebug &log) {
+ log << "You are calling a Q_INVOKABLE constructor of" << t.typeName()
+ << "which is uncreatable in QML.";
+ });
+ }
}
bool QQmlTypeWrapper::isSingleton() const
@@ -136,17 +195,59 @@ QVariant QQmlTypeWrapper::toVariant() const
return QVariant::fromValue<QObject*>(e->singletonInstance<QObject*>(type));
}
+ReturnedValue QQmlTypeWrapper::method_hasInstance(
+ const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
+{
+ // we want to immediately call instanceOf rather than going through Function
+
+ if (!argc)
+ return Encode(false);
+ if (const Object *o = thisObject->as<Object>())
+ return o->instanceOf(argv[0]);
+ return Encode(false);
+}
+
+ReturnedValue QQmlTypeWrapper::method_toString(
+ const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ const QQmlTypeWrapper *typeWrapper = thisObject->as<QQmlTypeWrapper>();
+ if (!typeWrapper)
+ RETURN_UNDEFINED();
+
+ const QString name = typeWrapper->d()->type().qmlTypeName();
+ return Encode(b->engine()->newString(name.isEmpty()
+ ? QLatin1String("Unknown Type")
+ : name));
+}
+
+void QQmlTypeWrapper::initProto(ExecutionEngine *v4)
+{
+ if (v4->typeWrapperPrototype()->d_unchecked())
+ return;
+
+ Scope scope(v4);
+ ScopedObject o(scope, v4->newObject());
+
+ o->defineDefaultProperty(v4->symbol_hasInstance(), method_hasInstance, 1, Attr_ReadOnly);
+ o->defineDefaultProperty(v4->id_toString(), method_toString, 0);
+ o->setPrototypeOf(v4->functionPrototype());
+
+ v4->jsObjects[QV4::ExecutionEngine::TypeWrapperProto] = o->d();
+}
// Returns a type wrapper for type t on o. This allows access of enums, and attached properties.
ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlType &t,
Heap::QQmlTypeWrapper::TypeNameMode mode)
{
Q_ASSERT(t.isValid());
- Scope scope(engine);
+ initProto(engine);
- Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>(
- mode, o, t.priv()));
- return w.asReturnedValue();
+ QV4::MemoryManager *mm = engine->memoryManager;
+
+ if (const QMetaObject *mo = t.metaObject(); !mo || mo->constructorCount() == 0)
+ return mm->allocate<QQmlTypeWrapper>(mode, o, t.priv())->asReturnedValue();
+
+ return mm->allocate<QQmlTypeConstructor>(mode, o, t.priv())->asReturnedValue();
}
// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
@@ -157,6 +258,8 @@ ReturnedValue QQmlTypeWrapper::create(
{
Q_ASSERT(t);
Q_ASSERT(importNamespace);
+ initProto(engine);
+
Scope scope(engine);
Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>(
@@ -203,7 +306,8 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
if (QObject *qobjectSingleton = enginePrivate->singletonInstance<QObject*>(type)) {
// check for enum value
- const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ const bool includeEnums
+ = w->d()->typeNameMode() == Heap::QQmlTypeWrapper::IncludeEnums;
if (includeEnums && name->startsWithUpper()) {
bool ok = false;
int value = enumForSingleton(v4, name, type, &ok);
@@ -278,14 +382,11 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
// Fall through to base implementation
- } else if (w->d()->typeNamespace) {
- Q_ASSERT(w->d()->importNamespace);
- QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(
- name, w->d()->importNamespace, QQmlTypeLoader::get(enginePrivate));
-
+ } else if (w->d()->kind() == Heap::QQmlTypeWrapper::Namespace) {
+ const QQmlTypeNameCache::Result r = w->d()->queryNamespace(name, enginePrivate);
if (r.isValid()) {
if (r.type.isValid()) {
- return create(scope.engine, object, r.type, w->d()->mode);
+ return create(scope.engine, object, r.type, w->d()->typeNameMode());
} else if (r.scriptIndex != -1) {
QV4::ScopedObject scripts(scope, context->importedScripts().valueRef());
return scripts->get(r.scriptIndex);
@@ -389,15 +490,16 @@ bool QQmlTypeWrapper::virtualIsEqualTo(Managed *a, Managed *b)
return false;
}
-static ReturnedValue instanceOfQObject(const QV4::QQmlTypeWrapper *typeWrapper, const QObjectWrapper *objectWrapper)
+static ReturnedValue instanceOfQObject(
+ const QV4::QQmlTypeWrapper *typeWrapper, QObject *wrapperObject)
{
QV4::ExecutionEngine *engine = typeWrapper->internalClass()->engine;
// in case the wrapper outlived the QObject*
- const QObject *wrapperObject = objectWrapper->object();
if (!wrapperObject)
return engine->throwTypeError();
- const QMetaType myTypeId = typeWrapper->d()->type().typeId();
+ const QQmlType type = typeWrapper->d()->type();
+ const QMetaType myTypeId = type.typeId();
QQmlMetaObject myQmlType;
if (!myTypeId.isValid()) {
// we're a composite type; a composite type cannot be equal to a
@@ -422,7 +524,12 @@ static ReturnedValue instanceOfQObject(const QV4::QQmlTypeWrapper *typeWrapper,
const QMetaObject *theirType = wrapperObject->metaObject();
- return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType));
+ if (QQmlMetaObject::canConvert(theirType, myQmlType))
+ return Encode(true);
+ else if (type.isValueType())
+ return Encode::undefined();
+ else
+ return Encode(false);
}
ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const Value &var)
@@ -431,21 +538,46 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
const QV4::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::QQmlTypeWrapper *>(typeObject);
if (const QObjectWrapper *objectWrapper = var.as<QObjectWrapper>())
- return instanceOfQObject(typeWrapper, objectWrapper);
+ return instanceOfQObject(typeWrapper, objectWrapper->object());
+
+ if (const QQmlTypeWrapper *varTypeWrapper = var.as<QQmlTypeWrapper>()) {
+ // Singleton or attachment
+ if (QObject *varObject = varTypeWrapper->object())
+ return instanceOfQObject(typeWrapper, varObject);
+ }
const QQmlType type = typeWrapper->d()->type();
- if (type.isValueType()) {
+
+ // If the target type is an object type we want null.
+ if (!type.isValueType())
+ return Encode(false);
+
+ const auto canCastValueType = [&]() -> bool {
if (const QQmlValueTypeWrapper *valueWrapper = var.as<QQmlValueTypeWrapper>()) {
- return QV4::Encode(QQmlMetaObject::canConvert(valueWrapper->metaObject(),
- type.metaObjectForValueType()));
+ return QQmlMetaObject::canConvert(
+ valueWrapper->metaObject(), type.metaObjectForValueType());
}
- // We want "foo as valuetype" to return undefined if it doesn't match.
- return Encode::undefined();
- }
+ switch (type.typeId().id()) {
+ case QMetaType::Void:
+ return var.isUndefined();
+ case QMetaType::QVariant:
+ return true; // Everything is a var
+ case QMetaType::Int:
+ return var.isInteger();
+ case QMetaType::Double:
+ return var.isDouble(); // Integers are also doubles
+ case QMetaType::QString:
+ return var.isString();
+ case QMetaType::Bool:
+ return var.isBoolean();
+ }
- // If the target type is an object type we want null.
- return Encode(false);
+ return false;
+ };
+
+ // We want "foo as valuetype" to return undefined if it doesn't match.
+ return canCastValueType() ? Encode(true) : Encode::undefined();
}
ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
@@ -469,7 +601,8 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
- const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ const bool includeEnums
+ = w->d()->typeNameMode() == Heap::QQmlTypeWrapper::IncludeEnums;
if (!includeEnums || !name->startsWithUpper()) {
QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
if (ddata && ddata->propertyCache) {
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index 717efaf20e..fa859dd118 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -19,7 +19,8 @@
#include <QtCore/qpointer.h>
#include <private/qv4value_p.h>
-#include <private/qv4object_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4qmetaobjectwrapper_p.h>
QT_BEGIN_NAMESPACE
@@ -32,26 +33,65 @@ namespace QV4 {
namespace Heap {
-struct QQmlTypeWrapper : Object {
- enum TypeNameMode {
- IncludeEnums,
- ExcludeEnums
+struct QQmlTypeWrapper : FunctionObject {
+
+ enum TypeNameMode : quint8 {
+ ExcludeEnums = 0x0,
+ IncludeEnums = 0x1,
+ TypeNameModeMask = 0x1,
+ };
+
+ enum Kind : quint8 {
+ Type = 0x0,
+ Namespace = 0x2,
+ KindMask = 0x2
};
void init(TypeNameMode m, QObject *o, const QQmlTypePrivate *type);
void init(TypeNameMode m, QObject *o, QQmlTypeNameCache *type, const QQmlImportRef *import);
void destroy();
- TypeNameMode mode;
- QV4QPointer<QObject> object;
+
+ const QMetaObject *metaObject() const { return type().metaObject(); }
+ QMetaType metaType() const { return type().typeId(); }
QQmlType type() const;
+ TypeNameMode typeNameMode() const { return TypeNameMode(flags & TypeNameModeMask); }
+ Kind kind() const { return Kind(flags & KindMask); }
+
+ const QQmlPropertyData *ensureConstructorsCache(
+ const QMetaObject *metaObject, QMetaType metaType)
+ {
+ Q_ASSERT(kind() == Type);
+ if (!t.constructors && metaObject) {
+ t.constructors = QMetaObjectWrapper::createConstructors(metaObject, metaType);
+ warnIfUncreatable();
+ }
+ return t.constructors;
+ }
+ void warnIfUncreatable() const;
+
+ QQmlTypeNameCache::Result queryNamespace(
+ const QV4::String *name, QQmlEnginePrivate *enginePrivate) const;
- const QQmlTypePrivate *typePrivate;
- QQmlTypeNameCache *typeNamespace;
- const QQmlImportRef *importNamespace;
+ QV4QPointer<QObject> object;
+
+ union {
+ struct {
+ const QQmlTypePrivate *typePrivate;
+ const QQmlPropertyData *constructors;
+ } t;
+ struct {
+ QQmlTypeNameCache *typeNamespace;
+ const QQmlImportRef *importNamespace;
+ } n;
+ };
+
+ quint8 flags;
};
+using QQmlTypeConstructor = QQmlTypeWrapper;
+
struct QQmlScopedEnumWrapper : Object {
void init() { Object::init(); }
void destroy();
@@ -62,9 +102,10 @@ struct QQmlScopedEnumWrapper : Object {
}
-struct Q_QML_EXPORT QQmlTypeWrapper : Object
+struct Q_QML_EXPORT QQmlTypeWrapper : FunctionObject
{
- V4_OBJECT2(QQmlTypeWrapper, Object)
+ V4_OBJECT2(QQmlTypeWrapper, FunctionObject)
+ V4_PROTOTYPE(typeWrapperPrototype)
V4_NEEDS_DESTROY
bool isSingleton() const;
@@ -74,6 +115,8 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object
QVariant toVariant() const;
+ static void initProto(ExecutionEngine *v4);
+
static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlType &,
Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums);
static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlRefPointer<QQmlTypeNameCache> &, const QQmlImportRef *,
@@ -95,6 +138,25 @@ protected:
static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p);
static bool virtualIsEqualTo(Managed *that, Managed *o);
static ReturnedValue virtualInstanceOf(const Object *typeObject, const Value &var);
+
+private:
+ static ReturnedValue method_hasInstance(
+ const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_toString(
+ const FunctionObject *b, const Value *thisObject, const Value *, int);
+};
+
+struct QQmlTypeConstructor : QQmlTypeWrapper
+{
+ V4_OBJECT2(QQmlTypeConstructor, QQmlTypeWrapper)
+
+ static ReturnedValue virtualCallAsConstructor(
+ const FunctionObject *f, const Value *argv, int argc, const Value *)
+ {
+ Q_ASSERT(f->as<QQmlTypeWrapper>());
+ return QMetaObjectWrapper::construct(
+ static_cast<const QQmlTypeWrapper *>(f)->d(), argv, argc);
+ }
};
struct Q_QML_EXPORT QQmlScopedEnumWrapper : Object
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 8815c914ce..dd23547c04 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -111,12 +111,11 @@ struct Q_QML_EXPORT QQmlPointFValueType
Q_GADGET
QML_VALUE_TYPE(point)
QML_FOREIGN(QPointF)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlPointFValueType)
QML_STRUCTURED_VALUE
public:
- QQmlPointFValueType() = default;
+ Q_INVOKABLE QQmlPointFValueType() = default;
Q_INVOKABLE QQmlPointFValueType(const QPoint &point) : v(point) {}
Q_INVOKABLE QString toString() const;
qreal x() const;
@@ -135,7 +134,6 @@ struct Q_QML_EXPORT QQmlPointValueType
Q_GADGET
QML_ANONYMOUS
QML_FOREIGN(QPoint)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlPointValueType)
QML_STRUCTURED_VALUE
@@ -159,12 +157,11 @@ struct Q_QML_EXPORT QQmlSizeFValueType
Q_GADGET
QML_VALUE_TYPE(size)
QML_FOREIGN(QSizeF)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlSizeFValueType)
QML_STRUCTURED_VALUE
public:
- QQmlSizeFValueType() = default;
+ Q_INVOKABLE QQmlSizeFValueType() = default;
Q_INVOKABLE QQmlSizeFValueType(const QSize &size) : v(size) {}
Q_INVOKABLE QString toString() const;
qreal width() const;
@@ -183,7 +180,6 @@ struct Q_QML_EXPORT QQmlSizeValueType
Q_GADGET
QML_ANONYMOUS
QML_FOREIGN(QSize)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlSizeValueType)
QML_STRUCTURED_VALUE
@@ -213,12 +209,11 @@ struct Q_QML_EXPORT QQmlRectFValueType
Q_GADGET
QML_VALUE_TYPE(rect)
QML_FOREIGN(QRectF)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlRectFValueType)
QML_STRUCTURED_VALUE
public:
- QQmlRectFValueType() = default;
+ Q_INVOKABLE QQmlRectFValueType() = default;
Q_INVOKABLE QQmlRectFValueType(const QRect &rect) : v(rect) {}
Q_INVOKABLE QString toString() const;
qreal x() const;
@@ -253,7 +248,6 @@ struct Q_QML_EXPORT QQmlRectValueType
Q_GADGET
QML_ANONYMOUS
QML_FOREIGN(QRect)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlRectValueType)
QML_STRUCTURED_VALUE
@@ -284,7 +278,6 @@ namespace QQmlEasingEnums
{
Q_NAMESPACE_EXPORT(Q_QML_EXPORT)
QML_NAMED_ELEMENT(Easing)
-QML_ADDED_IN_VERSION(2, 0)
enum Type {
Linear = QEasingCurve::Linear,
@@ -323,7 +316,6 @@ struct Q_QML_EXPORT QQmlEasingValueType
Q_GADGET
QML_ANONYMOUS
QML_FOREIGN(QEasingCurve)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlEasingValueType)
QML_STRUCTURED_VALUE
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 7075d0f5f6..a85601e5b9 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -3,41 +3,34 @@
#include "qqmlvaluetypewrapper_p.h"
-#include <private/qqmlvaluetype_p.h>
#include <private/qqmlbinding_p.h>
-#include <private/qqmlglobal_p.h>
#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmlvaluetype_p.h>
-#include <private/qv4engine_p.h>
-#include <private/qv4functionobject_p.h>
-#include <private/qv4variantobject_p.h>
#include <private/qv4alloca_p.h>
-#include <private/qv4stackframe_p.h>
-#include <private/qv4objectiterator_p.h>
-#include <private/qv4qobjectwrapper_p.h>
-#include <private/qv4identifiertable_p.h>
-#include <private/qv4lookup_p.h>
-#include <private/qv4sequenceobject_p.h>
#include <private/qv4arraybuffer_p.h>
#include <private/qv4dateobject_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4identifiertable_p.h>
#include <private/qv4jsonobject_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4stackframe_p.h>
+#include <private/qv4variantobject_p.h>
+
+#include <QtCore/qline.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qloggingcategory.h>
+
#if QT_CONFIG(regularexpression)
#include <private/qv4regexpobject_p.h>
#endif
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
-#endif
-#include <QtCore/qloggingcategory.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/QLine>
-#include <QtCore/QLineF>
-#include <QtCore/QSize>
-#include <QtCore/QSizeF>
-#include <QtCore/QTimeZone>
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
+Q_DECLARE_LOGGING_CATEGORY(lcBuiltinsBindingRemoval)
DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeWrapper);
@@ -304,7 +297,7 @@ static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
{
if (isFunction) {
// calling a Q_INVOKABLE function of a value type
- return QV4::QObjectMethod::create(engine->rootContext(), valueTypeWrapper, coreIndex);
+ return QV4::QObjectMethod::create(engine, valueTypeWrapper, coreIndex);
}
const QMetaObject *metaObject = valueTypeWrapper->metaObject();
@@ -785,7 +778,7 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
- QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
+ QV4::Scoped<JavaScriptFunctionObject> f(scope, bindingFunction->bindingFunction());
QV4::ScopedContext ctx(scope, f->scope());
QQmlBinding *newBinding = QQmlBinding::create(&cacheData, f->function(), referenceObject, context, ctx);
newBinding->setSourceLocation(bindingFunction->currentLocation());
@@ -796,12 +789,12 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
QQmlPropertyPrivate::setBinding(newBinding);
return true;
} else if (referenceObject) {
- if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
+ if (Q_UNLIKELY(lcBuiltinsBindingRemoval().isInfoEnabled())) {
if (auto binding = QQmlPropertyPrivate::binding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd.coreIndex()))) {
Q_ASSERT(binding->kind() == QQmlAbstractBinding::QmlBinding);
const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
const auto stackFrame = v4->currentStackFrame;
- qCInfo(lcBindingRemoval,
+ qCInfo(lcBuiltinsBindingRemoval,
"Overwriting binding on %s::%s which was initially bound at %s by setting \"%s\" at %s:%d",
referenceObject->metaObject()->className(), referenceObject->metaObject()->property(referencePropertyIndex).name(),
qPrintable(qmlBinding->expressionIdentifier()),
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index 5b3894a07f..97709dfb4c 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -19,14 +19,6 @@
#include <private/qtqmlglobal_p.h>
#include <private/qv4referenceobject_p.h>
-#include <private/qqmlpropertycache_p.h>
-#include <private/qqmltype_p_p.h>
-#include <private/qqmltypewrapper_p.h>
-#include <private/qv4object_p.h>
-#include <private/qv4qobjectwrapper_p.h>
-#include <private/qv4sequenceobject_p.h>
-#include <private/qv4value_p.h>
-#include <private/qv4referenceobject_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 5f3b6975ca..dffddd2e0d 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -1141,7 +1141,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
QV4::Scope scope(v4);
- QV4::ScopedFunctionObject function(scope, method(id));
+ QV4::Scoped<QV4::JavaScriptFunctionObject> function(scope, method(id));
if (!function) {
// The function was not compiled. There are some exceptional cases which the
// expression rewriter does not rewrite properly (e.g., \r-terminated lines
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index c5d18860db..b4800584a3 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1708,7 +1708,7 @@ DEFINE_OBJECT_VTABLE(QQmlXMLHttpRequestWrapper);
void Heap::QQmlXMLHttpRequestCtor::init(ExecutionEngine *engine)
{
- Heap::FunctionObject::init(engine->rootContext(), QStringLiteral("XMLHttpRequest"));
+ Heap::FunctionObject::init(engine, QStringLiteral("XMLHttpRequest"));
Scope scope(engine);
Scoped<QV4::QQmlXMLHttpRequestCtor> ctor(scope, this);
diff --git a/src/qml/qqmlbuiltins_p.h b/src/qml/qqmlbuiltins_p.h
index edf2579760..338bcf68a9 100644
--- a/src/qml/qqmlbuiltins_p.h
+++ b/src/qml/qqmlbuiltins_p.h
@@ -15,10 +15,8 @@
// We mean it.
//
-// QmlBuiltins does not link QtQml - rather the other way around. Still, we can use the QtQml
-// headers here. This works because we explicitly include the QtQml include directories in the
-// manual moc call.
#include <private/qqmlcomponentattached_p.h>
+
#include <QtQml/qjsvalue.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlscriptstring.h>
@@ -35,6 +33,9 @@
#include <QtCore/qvariantmap.h>
#include <QtCore/qtypes.h>
#include <QtCore/qchar.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
+#include <QtCore/qjsonarray.h>
#include <climits>
@@ -119,14 +120,24 @@ struct QQmlIntForeign
QML_VALUE_TYPE(int)
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(int)
- QML_PRIMITIVE_ALIAS(qint32)
- QML_PRIMITIVE_ALIAS(int32_t)
#ifdef QML_SIZE_IS_32BIT
+ // Keep qsizetype as primitive alias. We want it as separate type.
QML_PRIMITIVE_ALIAS(qsizetype)
#endif
-#ifdef QML_LONG_IS_32BIT
- QML_PRIMITIVE_ALIAS(long)
-#endif
+};
+
+struct QQmlQint32Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(qint32)
+ QML_USING(int)
+};
+
+struct QQmlInt32TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(int32_t)
+ QML_USING(int)
};
struct QQmlDoubleForeign
@@ -136,9 +147,6 @@ struct QQmlDoubleForeign
QML_VALUE_TYPE(double)
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(double)
-#if !defined(QT_COORD_TYPE) || defined(QT_COORD_TYPE_IS_DOUBLE)
- QML_PRIMITIVE_ALIAS(qreal)
-#endif
};
struct QQmlStringForeign
@@ -213,10 +221,13 @@ struct QQmlQint8Foreign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(qint8)
- QML_PRIMITIVE_ALIAS(int8_t)
-#if CHAR_MAX == SCHAR_MAX
- QML_PRIMITIVE_ALIAS(char)
-#endif
+};
+
+struct QQmlInt8TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(int8_t)
+ QML_USING(qint8)
};
struct QQmlQuint8Foreign
@@ -225,10 +236,32 @@ struct QQmlQuint8Foreign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(quint8)
- QML_PRIMITIVE_ALIAS(uint8_t)
- QML_PRIMITIVE_ALIAS(uchar)
+};
+
+struct QQmlUint8TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(uint8_t)
+ QML_USING(quint8)
+};
+
+struct QQmlUcharForeign
+{
+ Q_GADGET
+ QML_FOREIGN(uchar)
+ QML_USING(quint8)
+};
+
+struct QQmlCharForeign
+{
+ Q_GADGET
+ QML_FOREIGN(char)
#if CHAR_MAX == UCHAR_MAX
- QML_PRIMITIVE_ALIAS(char)
+ QML_USING(quint8)
+#elif CHAR_MAX == SCHAR_MAX
+ QML_USING(qint8)
+#else
+# error char is neither quint8 nor qint8
#endif
};
@@ -238,8 +271,20 @@ struct QQmlShortForeign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(short)
- QML_PRIMITIVE_ALIAS(qint16)
- QML_PRIMITIVE_ALIAS(int16_t)
+};
+
+struct QQmlQint16Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(qint16)
+ QML_USING(short)
+};
+
+struct QQmlInt16TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(int16_t)
+ QML_USING(short)
};
struct QQmlUshortForeign
@@ -248,8 +293,20 @@ struct QQmlUshortForeign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(ushort)
- QML_PRIMITIVE_ALIAS(quint16)
- QML_PRIMITIVE_ALIAS(uint16_t)
+};
+
+struct QQmlQuint16Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(quint16)
+ QML_USING(ushort)
+};
+
+struct QQmlUint16TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(uint16_t)
+ QML_USING(ushort)
};
struct QQmlUintForeign
@@ -258,11 +315,20 @@ struct QQmlUintForeign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(uint)
- QML_PRIMITIVE_ALIAS(quint32)
- QML_PRIMITIVE_ALIAS(uint32_t)
-#ifdef QML_LONG_IS_32BIT
- QML_PRIMITIVE_ALIAS(ulong)
-#endif
+};
+
+struct QQmlQuint32Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(quint32)
+ QML_USING(uint)
+};
+
+struct QQmlUint32TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(uint32_t)
+ QML_USING(uint)
};
struct QQmlQlonglongForeign
@@ -271,26 +337,71 @@ struct QQmlQlonglongForeign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(qlonglong)
- QML_PRIMITIVE_ALIAS(qint64)
- QML_PRIMITIVE_ALIAS(int64_t)
-#ifdef QML_LONG_IS_64BIT
- QML_PRIMITIVE_ALIAS(long)
-#endif
#ifdef QML_SIZE_IS_64BIT
+ // Keep qsizetype as primitive alias. We want it as separate type.
QML_PRIMITIVE_ALIAS(qsizetype)
#endif
};
+struct QQmlQint64Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(qint64)
+ QML_USING(qlonglong)
+};
+
+struct QQmlInt64TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(int64_t)
+ QML_USING(qlonglong)
+};
+
+struct QQmlLongForeign
+{
+ Q_GADGET
+ QML_FOREIGN(long)
+#if defined QML_LONG_IS_32BIT
+ QML_USING(int)
+#elif defined QML_LONG_IS_64BIT
+ QML_USING(qlonglong)
+#else
+# error long is neither 32bit nor 64bit
+#endif
+};
+
struct QQmlQulonglongForeign
{
Q_GADGET
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(qulonglong)
- QML_PRIMITIVE_ALIAS(quint64)
- QML_PRIMITIVE_ALIAS(uint64_t)
-#ifdef QML_LONG_IS_64BIT
- QML_PRIMITIVE_ALIAS(ulong)
+};
+
+struct QQmlQuint64Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(quint64)
+ QML_USING(qulonglong)
+};
+
+struct QQmlUint64TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(uint64_t)
+ QML_USING(qulonglong)
+};
+
+struct QQmlUlongForeign
+{
+ Q_GADGET
+ QML_FOREIGN(ulong)
+#if defined QML_LONG_IS_32BIT
+ QML_USING(uint)
+#elif defined QML_LONG_IS_64BIT
+ QML_USING(qulonglong)
+#else
+# error ulong is neither 32bit nor 64bit
#endif
};
@@ -300,8 +411,18 @@ struct QQmlFloatForeign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(float)
-#if defined(QT_COORD_TYPE) && defined(QT_COORD_TYPE_IS_FLOAT)
- QML_PRIMITIVE_ALIAS(qreal)
+};
+
+struct QQmlQRealForeign
+{
+ Q_GADGET
+ QML_FOREIGN(qreal)
+#if !defined(QT_COORD_TYPE) || defined(QT_COORD_TYPE_IS_DOUBLE)
+ QML_USING(double)
+#elif defined(QT_COORD_TYPE_IS_FLOAT)
+ QML_USING(float)
+#else
+# error qreal is neither float nor double
#endif
};
@@ -337,6 +458,14 @@ struct QQmlQByteArrayForeign
QML_FOREIGN(QByteArray)
};
+struct QQmlQByteArrayListForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QByteArrayList)
+ QML_SEQUENTIAL_CONTAINER(QByteArray)
+};
+
struct QQmlQStringListForeign
{
Q_GADGET
@@ -359,7 +488,13 @@ struct QQmlQObjectListForeign
QML_ANONYMOUS
QML_FOREIGN(QObjectList)
QML_SEQUENTIAL_CONTAINER(QObject*)
- QML_PRIMITIVE_ALIAS(QList<QObject*>)
+};
+
+struct QQmlQListQObjectForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QList<QObject*>)
+ QML_USING(QObjectList)
};
struct QQmlQJSValueForeign
@@ -393,6 +528,30 @@ struct QQmlV4FunctionPtrForeign
QML_EXTENDED(QQmlV4FunctionPtrForeign)
};
+struct QQmlQJsonObjectForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QJsonObject)
+ QML_EXTENDED_JAVASCRIPT(Object)
+};
+
+struct QQmlQJsonValueForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QJsonValue)
+ QML_EXTENDED_JAVASCRIPT(Object)
+};
+
+struct QQmlQJsonArrayForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QJsonArray)
+ QML_SEQUENTIAL_CONTAINER(QJsonValue)
+};
+
QT_END_NAMESPACE
#endif // QQMLBUILTINS_H
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index bc06d4ed51..5dcf89b863 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -30,7 +30,7 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
+Q_LOGGING_CATEGORY(lcQtQmlBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
enum class QQmlBindEntryKind: quint8 {
V4Value,
@@ -686,7 +686,7 @@ void QQmlBind::setTarget(const QQmlProperty &p)
void QQmlBindEntry::setTarget(QQmlBind *q, const QQmlProperty &p)
{
- if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
+ if (Q_UNLIKELY(lcQtQmlBindingRemoval().isInfoEnabled())) {
if (QObject *oldObject = prop.object()) {
QMetaProperty metaProp = oldObject->metaObject()->property(prop.index());
if (metaProp.hasNotifySignal()) {
@@ -1126,7 +1126,7 @@ void QQmlBind::targetValueChanged()
line = ddata->lineNumber;
}
- qCInfo(lcBindingRemoval,
+ qCInfo(lcQtQmlBindingRemoval,
"The target property of the Binding element created at %s:%d was changed from "
"elsewhere. This does not overwrite the binding. The target property will still be "
"updated when the value of the Binding element changes.",
diff --git a/src/qml/types/qqmlbind_p.h b/src/qml/types/qqmlbind_p.h
index aaefbc0618..d4c93ebe0a 100644
--- a/src/qml/types/qqmlbind_p.h
+++ b/src/qml/types/qqmlbind_p.h
@@ -15,7 +15,7 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
+#include <QtQmlMeta/qtqmlmetaexports.h>
#include <QtQml/qqml.h>
#include <QtCore/qobject.h>
@@ -23,7 +23,7 @@
QT_BEGIN_NAMESPACE
class QQmlBindPrivate;
-class Q_QML_EXPORT QQmlBind : public QObject, public QQmlPropertyValueSource, public QQmlParserStatus
+class Q_QMLMETA_EXPORT QQmlBind : public QObject, public QQmlPropertyValueSource, public QQmlParserStatus
{
public:
enum RestorationMode {
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 19363f9f76..99541a64dc 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -415,13 +415,12 @@ void QQmlConnections::connectSignalsToMethods()
auto *signal = new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
signal->setEnabled(d->enabled);
- QV4::ScopedFunctionObject method(
+ QV4::Scoped<QV4::JavaScriptFunctionObject> method(
scope, vmeMetaObject->vmeMethod(handler->coreIndex()));
QQmlBoundSignalExpression *expression = ctxtdata
? new QQmlBoundSignalExpression(
- target, signalIndex, ctxtdata, this,
- method->as<QV4::FunctionObject>()->function())
+ target, signalIndex, ctxtdata, this, method->function())
: nullptr;
signal->takeExpression(expression);
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index e0100aa452..f0852cda73 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -15,9 +15,11 @@
// We mean it.
//
-#include <qqml.h>
#include <private/qqmlcustomparser_p.h>
+#include <QtQmlMeta/qtqmlmetaexports.h>
+#include <QtQml/qqml.h>
+
#include <QtCore/qobject.h>
#include <QtCore/qstring.h>
@@ -26,7 +28,7 @@ QT_BEGIN_NAMESPACE
class QQmlBoundSignal;
class QQmlContext;
class QQmlConnectionsPrivate;
-class Q_QML_EXPORT QQmlConnections : public QObject, public QQmlParserStatus
+class Q_QMLMETA_EXPORT QQmlConnections : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlConnections)
diff --git a/src/qml/types/qqmllocaleenums_p.h b/src/qml/types/qqmllocaleenums_p.h
new file mode 100644
index 0000000000..771b74e5fb
--- /dev/null
+++ b/src/qml/types/qqmllocaleenums_p.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLLOCALEENUMS_H
+#define QQMLLOCALEENUMS_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtqmlglobal_p.h>
+#include <private/qqmllocale_p.h>
+
+#include <QtQmlMeta/qtqmlmetaexports.h>
+#include <QtQml/qqml.h>
+
+QT_REQUIRE_CONFIG(qml_locale);
+
+QT_BEGIN_NAMESPACE
+
+// Derive again so that we don't expose QQmlLocale as two different QML types
+// as that would be bad style.
+struct Q_QMLMETA_EXPORT QQmlLocaleEnums : public QQmlLocale
+{
+ Q_GADGET
+};
+
+// Use QML_FOREIGN_NAMESPACE so that we can expose QQmlLocaleEnums as a namespace
+// rather than a value type.
+namespace QQmlLocaleEnumsForeign
+{
+Q_NAMESPACE_EXPORT(Q_QMLMETA_EXPORT)
+QML_NAMED_ELEMENT(Locale)
+QML_ADDED_IN_VERSION(2, 2)
+QML_FOREIGN_NAMESPACE(QQmlLocaleEnums)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLLOCALEENUMS_H
+
diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/types/qqmlloggingcategory.cpp
index 8d7fd6c04d..c18be74525 100644
--- a/src/qml/qml/qqmlloggingcategory.cpp
+++ b/src/qml/types/qqmlloggingcategory.cpp
@@ -83,7 +83,7 @@
*/
QQmlLoggingCategory::QQmlLoggingCategory(QObject *parent)
- : QObject(parent)
+ : QQmlLoggingCategoryBase(parent)
, m_initialized(false)
{
}
@@ -102,11 +102,6 @@ QQmlLoggingCategory::DefaultLogLevel QQmlLoggingCategory::defaultLogLevel() cons
return m_defaultLogLevel;
}
-QLoggingCategory *QQmlLoggingCategory::category() const
-{
- return m_category.get();
-}
-
void QQmlLoggingCategory::classBegin()
{
}
@@ -114,12 +109,10 @@ void QQmlLoggingCategory::classBegin()
void QQmlLoggingCategory::componentComplete()
{
m_initialized = true;
- if (m_name.isNull()) {
+ if (m_name.isNull())
qmlWarning(this) << QLatin1String("Declaring the name of a LoggingCategory is mandatory and cannot be changed later");
- } else {
- auto category = std::make_unique<QLoggingCategory>(m_name.constData(), QtMsgType(m_defaultLogLevel));
- m_category.swap(category);
- }
+ else
+ setCategory(m_name.constData(), QtMsgType(m_defaultLogLevel));
}
void QQmlLoggingCategory::setDefaultLogLevel(DefaultLogLevel defaultLogLevel)
diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/types/qqmlloggingcategory_p.h
index 4a27e7e1d7..1f1f9abb63 100644
--- a/src/qml/qml/qqmlloggingcategory_p.h
+++ b/src/qml/types/qqmlloggingcategory_p.h
@@ -15,19 +15,21 @@
// We mean it.
//
-#include <QtCore/qobject.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qloggingcategory.h>
+#include <private/qqmlloggingcategorybase_p.h>
+
+#include <QtQmlMeta/qtqmlmetaexports.h>
-#include <QtQml/qqmlparserstatus.h>
#include <QtQml/qqml.h>
-#include <QtCore/private/qglobal_p.h>
+#include <QtQml/qqmlparserstatus.h>
-#include <memory>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
-class QQmlLoggingCategory : public QObject, public QQmlParserStatus
+class Q_QMLMETA_EXPORT QQmlLoggingCategory : public QQmlLoggingCategoryBase, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
@@ -55,14 +57,11 @@ public:
QString name() const;
void setName(const QString &name);
- QLoggingCategory *category() const;
-
void classBegin() override;
void componentComplete() override;
private:
QByteArray m_name;
- std::unique_ptr<QLoggingCategory> m_category;
DefaultLogLevel m_defaultLogLevel = Debug;
bool m_initialized;
};
diff --git a/src/qml/types/qqmltimer_p.h b/src/qml/types/qqmltimer_p.h
index e75b8bbe9d..f926262952 100644
--- a/src/qml/types/qqmltimer_p.h
+++ b/src/qml/types/qqmltimer_p.h
@@ -15,18 +15,18 @@
// We mean it.
//
-#include <qqml.h>
+#include <private/qtqmlglobal_p.h>
+#include <QtQmlMeta/qtqmlmetaexports.h>
+#include <QtQml/qqml.h>
#include <QtCore/qobject.h>
-#include <private/qtqmlglobal_p.h>
-
QT_REQUIRE_CONFIG(qml_animation);
QT_BEGIN_NAMESPACE
class QQmlTimerPrivate;
-class Q_QML_EXPORT QQmlTimer : public QObject, public QQmlParserStatus
+class Q_QMLMETA_EXPORT QQmlTimer : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlTimer)
diff --git a/src/qmlcompiler/CMakeLists.txt b/src/qmlcompiler/CMakeLists.txt
index 4e7d1cbf1c..445e5c7c12 100644
--- a/src/qmlcompiler/CMakeLists.txt
+++ b/src/qmlcompiler/CMakeLists.txt
@@ -16,6 +16,8 @@ qt_internal_add_module(QmlCompiler
qqmljscodegenerator.cpp qqmljscodegenerator_p.h
qqmljscompilepass_p.h
qqmljscompiler.cpp qqmljscompiler_p.h
+ qqmljscompilerstats.cpp qqmljscompilerstats_p.h
+ qqmljscompilerstatsreporter.cpp qqmljscompilerstatsreporter_p.h
qqmljsfunctioninitializer.cpp qqmljsfunctioninitializer_p.h
qqmljsimporter.cpp qqmljsimporter_p.h
qqmljsimportvisitor.cpp qqmljsimportvisitor_p.h
diff --git a/src/qmlcompiler/qdeferredpointer_p.h b/src/qmlcompiler/qdeferredpointer_p.h
index e4d5eb6df3..4bd3b18326 100644
--- a/src/qmlcompiler/qdeferredpointer_p.h
+++ b/src/qmlcompiler/qdeferredpointer_p.h
@@ -155,6 +155,14 @@ public:
return (m_factory && m_factory->isValid()) ? m_factory.data() : nullptr;
}
+ void resetFactory(const Factory& newFactory) const
+ {
+ const bool wasAlreadyLoaded = !factory();
+ *m_factory = newFactory;
+ if (wasAlreadyLoaded)
+ lazyLoad();
+ }
+
private:
friend class QDeferredWeakPointer<T>;
diff --git a/src/qmlcompiler/qqmljsbasicblocks.cpp b/src/qmlcompiler/qqmljsbasicblocks.cpp
index 671cac0d25..392a8b9ba7 100644
--- a/src/qmlcompiler/qqmljsbasicblocks.cpp
+++ b/src/qmlcompiler/qqmljsbasicblocks.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qqmljsbasicblocks_p.h"
+#include "qqmljsutils_p.h"
#include <QtQml/private/qv4instr_moth_p.h>
@@ -101,15 +102,6 @@ void QQmlJSBasicBlocks::dumpDOTGraph()
}
}
-template<typename Container>
-void deduplicate(Container &container)
-{
- std::sort(container.begin(), container.end());
- auto erase = std::unique(container.begin(), container.end());
- container.erase(erase, container.end());
-}
-
-
QQmlJSCompilePass::BlocksAndAnnotations
QQmlJSBasicBlocks::run(const Function *function, QQmlJSAotCompiler::Flags compileFlags,
bool &basicBlocksValidationFailed)
@@ -156,7 +148,7 @@ QQmlJSBasicBlocks::run(const Function *function, QQmlJSAotCompiler::Flags compil
reset();
decode(byteCode.constData(), static_cast<uint>(byteCode.size()));
for (auto it = m_basicBlocks.begin(), end = m_basicBlocks.end(); it != end; ++it)
- deduplicate(it->second.jumpOrigins);
+ QQmlJSUtils::deduplicate(it->second.jumpOrigins);
}
if (compileFlags.testFlag(QQmlJSAotCompiler::ValidateBasicBlocks) || qv4ValidateBasicBlocks()) {
diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp
index e6529a07d9..75216358ec 100644
--- a/src/qmlcompiler/qqmljscodegenerator.cpp
+++ b/src/qmlcompiler/qqmljscodegenerator.cpp
@@ -76,17 +76,17 @@ QString QQmlJSCodeGenerator::metaTypeFromName(const QQmlJSScope::ConstPtr &type)
QString QQmlJSCodeGenerator::compositeListMetaType(const QString &elementName) const
{
return u"[](auto *aotContext) { static const auto t = QQmlPrivate::compositeListMetaType("
- "aotContext->compilationUnit, \""_s
+ "aotContext->compilationUnit, QStringLiteral(\""_s
+ elementName
- + u"\"); return t; }(aotContext)"_s;
+ + u"\")); return t; }(aotContext)"_s;
}
QString QQmlJSCodeGenerator::compositeMetaType(const QString &elementName) const
{
return u"[](auto *aotContext) { static const auto t = QQmlPrivate::compositeMetaType("
- "aotContext->compilationUnit, \""_s
+ "aotContext->compilationUnit, QStringLiteral(\""_s
+ elementName
- + u"\"); return t; }(aotContext)"_s;
+ + u"\")); return t; }(aotContext)"_s;
}
QString QQmlJSCodeGenerator::metaObject(const QQmlJSScope::ConstPtr &objectType)
@@ -359,7 +359,8 @@ void QQmlJSCodeGenerator::generate_Ret()
m_body += u" *static_cast<"_s
+ stored->augmentedInternalName()
+ u" *>(argv[0]) = "_s
- + conversion(m_state.accumulatorIn(), m_function->returnType, in)
+ + conversion(m_state.accumulatorIn(), m_function->returnType,
+ consumedAccumulatorVariableIn())
+ u";\n"_s;
} else if (m_typeResolver->registerContains(m_state.accumulatorIn(), contained)) {
m_body += u" const QMetaType returnType = "_s + contentType(m_state.accumulatorIn(), in)
@@ -369,7 +370,8 @@ void QQmlJSCodeGenerator::generate_Ret()
+ contentPointer(m_state.accumulatorIn(), in) + u");\n"_s;
} else {
m_body += u" const auto converted = "_s
- + conversion(m_state.accumulatorIn(), m_function->returnType, in) + u";\n"_s;
+ + conversion(m_state.accumulatorIn(), m_function->returnType,
+ consumedAccumulatorVariableIn()) + u";\n"_s;
m_body += u" const QMetaType returnType = "_s
+ contentType(m_function->returnType, u"converted"_s)
+ u";\n"_s;
@@ -2060,11 +2062,9 @@ bool QQmlJSCodeGenerator::inlineConsoleMethod(const QString &name, int argc, int
m_body += u" bool firstArgIsCategory = false;\n";
const QQmlJSRegisterContent firstArg = argc > 0 ? registerType(argv) : QQmlJSRegisterContent();
- // We could check for internalName == "QQmlLoggingCategory" here, but we don't want to
- // because QQmlLoggingCategory is not a builtin. Tying the specific internal name and
- // intheritance hierarchy in here would be fragile.
- // TODO: We could drop the check for firstArg in some cases if we made some base class
- // of QQmlLoggingCategory a builtin.
+ // We could check whether the first argument is a QQmlLoggingCategoryBase here, and we should
+ // because QQmlLoggingCategoryBase is now a builtin.
+ // TODO: The run time check for firstArg is obsolete.
const bool firstArgIsReference = argc > 0
&& m_typeResolver->containedType(firstArg)->isReferenceType();
@@ -3637,9 +3637,13 @@ void QQmlJSCodeGenerator::generateArithmeticOperation(
const QQmlJSRegisterContent originalOut = m_typeResolver->original(m_state.accumulatorOut());
m_body += m_state.accumulatorVariableOut;
m_body += u" = "_s;
+ const QString explicitCast
+ = m_typeResolver->equals(originalOut.storedType(), m_typeResolver->stringType())
+ ? originalOut.storedType()->internalName()
+ : QString();
m_body += conversion(
originalOut, m_state.accumulatorOut(),
- u'(' + lhs + u' ' + cppOperator + u' ' + rhs + u')');
+ explicitCast + u'(' + lhs + u' ' + cppOperator + u' ' + rhs + u')');
m_body += u";\n"_s;
}
diff --git a/src/qmlcompiler/qqmljscompiler.cpp b/src/qmlcompiler/qqmljscompiler.cpp
index 8ecc69d1c9..5aa8a62786 100644
--- a/src/qmlcompiler/qqmljscompiler.cpp
+++ b/src/qmlcompiler/qqmljscompiler.cpp
@@ -6,6 +6,7 @@
#include <private/qqmlirbuilder_p.h>
#include <private/qqmljsbasicblocks_p.h>
#include <private/qqmljscodegenerator_p.h>
+#include <private/qqmljscompilerstats_p.h>
#include <private/qqmljsfunctioninitializer_p.h>
#include <private/qqmljsimportvisitor_p.h>
#include <private/qqmljslexer_p.h>
@@ -679,7 +680,8 @@ std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> QQmlJSAotCompiler::co
const QString name = m_document->stringAt(irBinding.propertyNameIndex);
QQmlJSCompilePass::Function function = initializer.run(
context, name, astNode, irBinding, &error);
- const QQmlJSAotFunction aotFunction = doCompile(context, &function, &error);
+ const QQmlJSAotFunction aotFunction = doCompileAndRecordAotStats(
+ context, &function, &error, name, astNode->firstSourceLocation());
if (error.isValid()) {
// If it's a signal and the function just returns a closure, it's harmless.
@@ -703,7 +705,8 @@ std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> QQmlJSAotCompiler::co
&m_typeResolver, m_currentObject->location, m_currentScope->location);
QQmlJS::DiagnosticMessage error;
QQmlJSCompilePass::Function function = initializer.run(context, name, astNode, &error);
- const QQmlJSAotFunction aotFunction = doCompile(context, &function, &error);
+ const QQmlJSAotFunction aotFunction = doCompileAndRecordAotStats(
+ context, &function, &error, name, astNode->firstSourceLocation());
if (error.isValid())
return diagnose(error.message, QtWarningMsg, error.loc);
@@ -783,4 +786,26 @@ QQmlJSAotFunction QQmlJSAotCompiler::doCompile(
return error->isValid() ? compileError() : result;
}
+QQmlJSAotFunction QQmlJSAotCompiler::doCompileAndRecordAotStats(
+ const QV4::Compiler::Context *context, QQmlJSCompilePass::Function *function,
+ QQmlJS::DiagnosticMessage *error, const QString &name, QQmlJS::SourceLocation location)
+{
+ auto t1 = std::chrono::high_resolution_clock::now();
+ QQmlJSAotFunction result = doCompile(context, function, error);
+ auto t2 = std::chrono::high_resolution_clock::now();
+
+ if (QQmlJS::QQmlJSAotCompilerStats::recordAotStats()) {
+ QQmlJS::AotStatsEntry entry;
+ entry.codegenDuration = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1);
+ entry.functionName = name;
+ entry.errorMessage = error->message;
+ entry.line = location.startLine;
+ entry.column = location.startColumn;
+ entry.codegenSuccessful = !error->isValid();
+ QQmlJS::QQmlJSAotCompilerStats::addEntry(function->qmlScope->filePath(), entry);
+ }
+
+ return result;
+}
+
QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljscompiler_p.h b/src/qmlcompiler/qqmljscompiler_p.h
index e358f76fef..b687b5dba3 100644
--- a/src/qmlcompiler/qqmljscompiler_p.h
+++ b/src/qmlcompiler/qqmljscompiler_p.h
@@ -22,6 +22,7 @@
#include <private/qqmlirbuilder_p.h>
#include <private/qqmljscompilepass_p.h>
+#include <private/qqmljscompilerstats_p.h>
#include <private/qqmljsdiagnosticmessage_p.h>
#include <private/qqmljsimporter_p.h>
#include <private/qqmljslogger_p.h>
@@ -97,9 +98,14 @@ protected:
QQmlJSLogger *m_logger = nullptr;
private:
- QQmlJSAotFunction doCompile(
- const QV4::Compiler::Context *context, QQmlJSCompilePass::Function *function,
- QQmlJS::DiagnosticMessage *error);
+ QQmlJSAotFunction doCompile(const QV4::Compiler::Context *context,
+ QQmlJSCompilePass::Function *function,
+ QQmlJS::DiagnosticMessage *error);
+ QQmlJSAotFunction doCompileAndRecordAotStats(const QV4::Compiler::Context *context,
+ QQmlJSCompilePass::Function *function,
+ QQmlJS::DiagnosticMessage *error,
+ const QString &name,
+ QQmlJS::SourceLocation location);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlJSAotCompiler::Flags);
diff --git a/src/qmlcompiler/qqmljscompilerstats.cpp b/src/qmlcompiler/qqmljscompilerstats.cpp
new file mode 100644
index 0000000000..7cef0f39c3
--- /dev/null
+++ b/src/qmlcompiler/qqmljscompilerstats.cpp
@@ -0,0 +1,188 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qqmljscompilerstats_p.h"
+
+#include <QFile>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QTextStream>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+using namespace Qt::StringLiterals;
+
+std::unique_ptr<AotStats> QQmlJSAotCompilerStats::s_instance = std::make_unique<AotStats>();
+QString QQmlJSAotCompilerStats::s_moduleId;
+bool QQmlJSAotCompilerStats::s_recordAotStats = false;
+
+bool QQmlJS::AotStatsEntry::operator<(const AotStatsEntry &other) const
+{
+ if (line == other.line)
+ return column < other.column;
+ return line < other.line;
+}
+
+void AotStats::insert(const AotStats &other)
+{
+ for (const auto &[moduleUri, moduleStats] : other.m_entries.asKeyValueRange()) {
+ m_entries[moduleUri].insert(moduleStats);
+ }
+}
+
+std::optional<QList<QString>> extractAotstatsFilesList(const QString &aotstatsListPath)
+{
+ QFile aotstatsListFile(aotstatsListPath);
+ if (!aotstatsListFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ qDebug().noquote() << u"Could not open \"%1\" for reading"_s.arg(aotstatsListFile.fileName());
+ return std::nullopt;
+ }
+
+ QStringList aotstatsFiles;
+ QTextStream stream(&aotstatsListFile);
+ while (!stream.atEnd())
+ aotstatsFiles.append(stream.readLine());
+
+ return aotstatsFiles;
+}
+
+std::optional<AotStats> AotStats::parseAotstatsFile(const QString &aotstatsPath)
+{
+ QFile file(aotstatsPath);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ qDebug().noquote() << u"Could not open \"%1\""_s.arg(aotstatsPath);
+ return std::nullopt;
+ }
+
+ return AotStats::fromJsonDocument(QJsonDocument::fromJson(file.readAll()));
+}
+
+std::optional<AotStats> AotStats::aggregateAotstatsList(const QString &aotstatsListPath)
+{
+ const auto aotstatsFiles = extractAotstatsFilesList(aotstatsListPath);
+ if (!aotstatsFiles.has_value())
+ return std::nullopt;
+
+ AotStats aggregated;
+ if (aotstatsFiles->empty())
+ return aggregated;
+
+ for (const auto &aotstatsFile : aotstatsFiles.value()) {
+ auto parsed = parseAotstatsFile(aotstatsFile);
+ if (!parsed.has_value())
+ return std::nullopt;
+ aggregated.insert(parsed.value());
+ }
+
+ return aggregated;
+}
+
+AotStats AotStats::fromJsonDocument(const QJsonDocument &document)
+{
+ QJsonArray modulesArray = document.array();
+
+ QQmlJS::AotStats result;
+ for (const auto &modulesArrayEntry : modulesArray) {
+ const auto &moduleObject = modulesArrayEntry.toObject();
+ QString moduleId = moduleObject[u"moduleId"_s].toString();
+ const QJsonArray &filesArray = moduleObject[u"moduleFiles"_s].toArray();
+
+ QHash<QString, QList<AotStatsEntry>> files;
+ for (const auto &filesArrayEntry : filesArray) {
+ const QJsonObject &fileObject = filesArrayEntry.toObject();
+ QString filepath = fileObject[u"filepath"_s].toString();
+ const QJsonArray &statsArray = fileObject[u"entries"_s].toArray();
+
+ QList<AotStatsEntry> stats;
+ for (const auto &statsArrayEntry : statsArray) {
+ const auto &statsObject = statsArrayEntry.toObject();
+ QQmlJS::AotStatsEntry stat;
+ auto micros = statsObject[u"durationMicroseconds"_s].toInteger();
+ stat.codegenDuration = std::chrono::microseconds(micros);
+ stat.functionName = statsObject[u"functionName"_s].toString();
+ stat.errorMessage = statsObject[u"errorMessage"_s].toString();
+ stat.line = statsObject[u"line"_s].toInt();
+ stat.column = statsObject[u"column"_s].toInt();
+ stat.codegenSuccessful = statsObject[u"codegenSuccessfull"_s].toBool();
+ stats.append(std::move(stat));
+ }
+
+ std::sort(stats.begin(), stats.end());
+ files[filepath] = std::move(stats);
+ }
+
+ result.m_entries[moduleId] = std::move(files);
+ }
+
+ return result;
+}
+
+QJsonDocument AotStats::toJsonDocument() const
+{
+ QJsonArray modulesArray;
+ for (auto it1 = m_entries.begin(); it1 != m_entries.end(); ++it1) {
+ const QString moduleId = it1.key();
+ const QHash<QString, QList<AotStatsEntry>> &files = it1.value();
+
+ QJsonArray filesArray;
+ for (auto it2 = files.begin(); it2 != files.end(); ++it2) {
+ const QString &filename = it2.key();
+ const QList<AotStatsEntry> &stats = it2.value();
+
+ QJsonArray statsArray;
+ for (const auto &stat : stats) {
+ QJsonObject statObject;
+ auto micros = static_cast<qint64>(stat.codegenDuration.count());
+ statObject.insert(u"durationMicroseconds", micros);
+ statObject.insert(u"functionName", stat.functionName);
+ statObject.insert(u"errorMessage", stat.errorMessage);
+ statObject.insert(u"line", stat.line);
+ statObject.insert(u"column", stat.column);
+ statObject.insert(u"codegenSuccessfull", stat.codegenSuccessful);
+ statsArray.append(statObject);
+ }
+
+ QJsonObject o;
+ o.insert(u"filepath"_s, filename);
+ o.insert(u"entries"_s, statsArray);
+ filesArray.append(o);
+ }
+
+ QJsonObject o;
+ o.insert(u"moduleId"_s, moduleId);
+ o.insert(u"moduleFiles"_s, filesArray);
+ modulesArray.append(o);
+ }
+
+ return QJsonDocument(modulesArray);
+}
+
+void AotStats::addEntry(
+ const QString &moduleId, const QString &filepath, const AotStatsEntry &entry)
+{
+ m_entries[moduleId][filepath].append(entry);
+}
+
+bool AotStats::saveToDisk(const QString &filepath) const
+{
+ QFile file(filepath);
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
+ qDebug().noquote() << u"Could not open \"%1\""_s.arg(filepath);
+ return false;
+ }
+
+ file.write(this->toJsonDocument().toJson(QJsonDocument::Indented));
+ return true;
+}
+
+void QQmlJSAotCompilerStats::addEntry(const QString &filepath, const QQmlJS::AotStatsEntry &entry)
+{
+ QQmlJSAotCompilerStats::instance()->addEntry(s_moduleId, filepath, entry);
+}
+
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljscompilerstats_p.h b/src/qmlcompiler/qqmljscompilerstats_p.h
new file mode 100644
index 0000000000..53ebb9f777
--- /dev/null
+++ b/src/qmlcompiler/qqmljscompilerstats_p.h
@@ -0,0 +1,92 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QQMLJSCOMPILERSTATS_P_H
+#define QQMLJSCOMPILERSTATS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#include <qtqmlcompilerexports.h>
+
+#include <QHash>
+#include <QJsonDocument>
+
+#include <private/qqmljsdiagnosticmessage_p.h>
+#include <private/qqmljssourcelocation_p.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+struct Q_QMLCOMPILER_EXPORT AotStatsEntry
+{
+ std::chrono::microseconds codegenDuration;
+ QString functionName;
+ QString errorMessage;
+ int line = 0;
+ int column = 0;
+ bool codegenSuccessful = true;
+
+ bool operator<(const AotStatsEntry &) const;
+};
+
+class Q_QMLCOMPILER_EXPORT AotStats
+{
+ friend class QQmlJSAotCompilerStats;
+
+public:
+ const QHash<QString, QHash<QString, QList<AotStatsEntry>>> &entries() const
+ {
+ return m_entries;
+ }
+
+ void addEntry(const QString &moduleId, const QString &filepath, const AotStatsEntry &entry);
+ void insert(const AotStats &other);
+
+ bool saveToDisk(const QString &filepath) const;
+
+ static std::optional<AotStats> parseAotstatsFile(const QString &aotstatsPath);
+ static std::optional<AotStats> aggregateAotstatsList(const QString &aotstatsListPath);
+
+ static AotStats fromJsonDocument(const QJsonDocument &);
+ QJsonDocument toJsonDocument() const;
+
+private:
+ // module Id -> filename -> stats m_entries
+ QHash<QString, QHash<QString, QList<AotStatsEntry>>> m_entries;
+};
+
+class Q_QMLCOMPILER_EXPORT QQmlJSAotCompilerStats
+{
+public:
+ static AotStats *instance() { return s_instance.get(); }
+
+ static bool recordAotStats() { return s_recordAotStats; }
+ static void setRecordAotStats(bool recordAotStats) { s_recordAotStats = recordAotStats; }
+
+ static QString moduleId() { return s_moduleId; }
+ static void setModuleId(const QString &moduleId) { s_moduleId = moduleId; }
+
+ static void addEntry(const QString &filepath, const QQmlJS::AotStatsEntry &entry);
+
+private:
+ static std::unique_ptr<AotStats> s_instance;
+ static QString s_moduleId;
+ static bool s_recordAotStats;
+};
+
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QQMLJSCOMPILERSTATS_P_H
diff --git a/src/qmlcompiler/qqmljscompilerstatsreporter.cpp b/src/qmlcompiler/qqmljscompilerstatsreporter.cpp
new file mode 100644
index 0000000000..1cb17f71fe
--- /dev/null
+++ b/src/qmlcompiler/qqmljscompilerstatsreporter.cpp
@@ -0,0 +1,118 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qqmljscompilerstatsreporter_p.h"
+
+#include <QFileInfo>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+using namespace Qt::StringLiterals;
+
+AotStatsReporter::AotStatsReporter(const AotStats &aotstats) : m_aotstats(aotstats)
+{
+ for (const auto &[moduleUri, fileEntries] : aotstats.entries().asKeyValueRange()) {
+ for (const auto &[filepath, statsEntries] : fileEntries.asKeyValueRange()) {
+ for (const auto &entry : statsEntries) {
+ m_fileCounters[moduleUri][filepath].codegens += 1;
+ if (entry.codegenSuccessful) {
+ m_fileCounters[moduleUri][filepath].successes += 1;
+ m_successDurations.append(entry.codegenDuration);
+ }
+ }
+ m_moduleCounters[moduleUri].codegens += m_fileCounters[moduleUri][filepath].codegens;
+ m_moduleCounters[moduleUri].successes += m_fileCounters[moduleUri][filepath].successes;
+ }
+ m_totalCounters.codegens += m_moduleCounters[moduleUri].codegens;
+ m_totalCounters.successes += m_moduleCounters[moduleUri].successes;
+ }
+}
+
+void AotStatsReporter::formatDetailedStats(QTextStream &s) const
+{
+ s << "############ AOT COMPILATION STATS ############\n";
+ for (const auto &[moduleUri, fileStats] : m_aotstats.entries().asKeyValueRange()) {
+ s << u"Module %1:\n"_s.arg(moduleUri);
+ if (fileStats.empty()) {
+ s << "No attempts at compiling a binding or function\n";
+ continue;
+ }
+
+ for (const auto &[filename, entries] : fileStats.asKeyValueRange()) {
+ s << u"--File %1\n"_s.arg(filename);
+ if (entries.empty()) {
+ s << " No attempts at compiling a binding or function\n";
+ continue;
+ }
+
+ int successes = m_fileCounters[moduleUri][filename].successes;
+ s << " " << formatSuccessRate(entries.size(), successes) << "\n";
+
+ for (const auto &stat : entries) {
+ s << u" %1: [%2:%3:%4]\n"_s.arg(stat.functionName)
+ .arg(QFileInfo(filename).fileName())
+ .arg(stat.line)
+ .arg(stat.column);
+ s << u" result: "_s << (stat.codegenSuccessful
+ ? u"Success\n"_s
+ : u"Error: "_s + stat.errorMessage + u'\n');
+ s << u" duration: %1us\n"_s.arg(stat.codegenDuration.count());
+ }
+ s << "\n";
+ }
+ }
+}
+
+void AotStatsReporter::formatSummary(QTextStream &s) const
+{
+ s << "############ AOT COMPILATION STATS SUMMARY ############\n";
+ if (m_totalCounters.codegens == 0) {
+ s << "No attempted compilations to Cpp for bindings or functions.\n";
+ return;
+ }
+
+ for (const auto &moduleUri : m_aotstats.entries().keys()) {
+ const auto &counters = m_moduleCounters[moduleUri];
+ s << u"Module %1: "_s.arg(moduleUri)
+ << formatSuccessRate(counters.codegens, counters.successes) << "\n";
+ }
+
+ s << "Total results: " << formatSuccessRate(m_totalCounters.codegens, m_totalCounters.successes);
+ s << "\n";
+
+ if (m_totalCounters.successes != 0) {
+ auto totalDuration = std::accumulate(m_successDurations.cbegin(), m_successDurations.cend(),
+ std::chrono::microseconds(0));
+ const auto averageDuration = totalDuration.count() / m_totalCounters.successes;
+ s << u"Successful codegens took an average of %1us\n"_s.arg(averageDuration);
+ }
+}
+
+QString AotStatsReporter::format() const
+{
+ QString output;
+ QTextStream s(&output);
+
+ formatDetailedStats(s);
+ formatSummary(s);
+
+ return output;
+}
+
+QString AotStatsReporter::formatSuccessRate(int codegens, int successes) const
+{
+ if (codegens == 0)
+ return u"No attempted compilations"_s;
+
+ return u"%1 of %2 (%3%4) bindings or functions compiled to Cpp successfully"_s
+ .arg(successes)
+ .arg(codegens)
+ .arg(double(successes) / codegens * 100, 0, 'g', 4)
+ .arg(u"%"_s);
+}
+
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljscompilerstatsreporter_p.h b/src/qmlcompiler/qqmljscompilerstatsreporter_p.h
new file mode 100644
index 0000000000..9acf4adac8
--- /dev/null
+++ b/src/qmlcompiler/qqmljscompilerstatsreporter_p.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QQMLJSCOMPILERSTATSREPORTER_P_H
+#define QQMLJSCOMPILERSTATSREPORTER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#include <QTextStream>
+
+#include <qtqmlcompilerexports.h>
+
+#include <private/qqmljscompilerstats_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class Q_QMLCOMPILER_EXPORT AotStatsReporter
+{
+public:
+ AotStatsReporter(const QQmlJS::AotStats &);
+
+ QString format() const;
+
+private:
+ void formatDetailedStats(QTextStream &) const;
+ void formatSummary(QTextStream &) const;
+ QString formatSuccessRate(int codegens, int successes) const;
+
+ const AotStats &m_aotstats;
+
+ struct Counters
+ {
+ int successes = 0;
+ int codegens = 0;
+ };
+
+ Counters m_totalCounters;
+ QHash<QString, Counters> m_moduleCounters;
+ QHash<QString, QHash<QString, Counters>> m_fileCounters;
+ QList<std::chrono::microseconds> m_successDurations;
+};
+
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QQMLJSCOMPILERSTATSREPORTER_P_H
diff --git a/src/qmlcompiler/qqmljsimporter.cpp b/src/qmlcompiler/qqmljsimporter.cpp
index bcc8e98434..ae5d1654f0 100644
--- a/src/qmlcompiler/qqmljsimporter.cpp
+++ b/src/qmlcompiler/qqmljsimporter.cpp
@@ -616,24 +616,30 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
Import result;
result.name = QStringLiteral("QML");
- QStringList qmltypesFiles = { QStringLiteral("builtins.qmltypes"),
- QStringLiteral("jsroot.qmltypes") };
- const auto importBuiltins = [&](const QStringList &imports) {
+ const auto importBuiltins = [&](const QString &qmltypesFile, const QStringList &imports) {
for (auto const &dir : imports) {
- QDirIterator it { dir, qmltypesFiles, QDir::NoFilter };
- while (it.hasNext() && !qmltypesFiles.isEmpty()) {
- readQmltypes(it.next(), &result.objects, &result.dependencies);
- qmltypesFiles.removeOne(it.fileName());
- }
+ const QDir importDir(dir);
+ if (!importDir.exists(qmltypesFile))
+ continue;
+
+ readQmltypes(
+ importDir.filePath(qmltypesFile), &result.objects, &result.dependencies);
setQualifiedNamesOn(result);
importDependencies(result, &builtins);
-
- if (qmltypesFiles.isEmpty())
- return;
+ return true;
}
+
+ return false;
};
- importBuiltins(m_importPaths);
+ // If the same name (such as "Qt") appears in the JS root and in the builtins,
+ // we want the builtins to override the JS root. Therefore, process jsroot first.
+ QStringList qmltypesFiles;
+ for (QString qmltypesFile : { "jsroot.qmltypes"_L1, "builtins.qmltypes"_L1 }) {
+ if (!importBuiltins(qmltypesFile, m_importPaths))
+ qmltypesFiles.append(std::move(qmltypesFile));
+ }
+
if (!qmltypesFiles.isEmpty()) {
const QString pathsString =
m_importPaths.isEmpty() ? u"<empty>"_s : m_importPaths.join(u"\n\t");
@@ -641,9 +647,13 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
"qrc). Import paths used:\n\t%2")
.arg(qmltypesFiles.join(u", "), pathsString),
QtWarningMsg, QQmlJS::SourceLocation() });
- importBuiltins({ u":/qt-project.org/qml/builtins"_s }); // use qrc as a "last resort"
+
+ // use qrc as a "last resort"
+ for (const QString &qmltypesFile : std::as_const(qmltypesFiles)) {
+ const bool found = importBuiltins(qmltypesFile, { u":/qt-project.org/qml/builtins"_s });
+ Q_ASSERT(found); // since qrc must cover it in all the bad cases
+ }
}
- Q_ASSERT(qmltypesFiles.isEmpty()); // since qrc must cover it in all the bad cases
// Process them together since there they have interdependencies that wouldn't get resolved
// otherwise
diff --git a/src/qmlcompiler/qqmljslinter.cpp b/src/qmlcompiler/qqmljslinter.cpp
index f135aef8ba..b5744b0c3d 100644
--- a/src/qmlcompiler/qqmljslinter.cpp
+++ b/src/qmlcompiler/qqmljslinter.cpp
@@ -244,7 +244,7 @@ std::vector<QQmlJSLinter::Plugin> QQmlJSLinter::loadPlugins(QStringList paths)
}
}
#endif
-
+ Q_UNUSED(paths)
return plugins;
}
diff --git a/src/qmlcompiler/qqmljsoptimizations.cpp b/src/qmlcompiler/qqmljsoptimizations.cpp
index ecef117c53..1d0a7cf415 100644
--- a/src/qmlcompiler/qqmljsoptimizations.cpp
+++ b/src/qmlcompiler/qqmljsoptimizations.cpp
@@ -3,6 +3,7 @@
#include "qqmljsoptimizations_p.h"
#include "qqmljsbasicblocks_p.h"
+#include "qqmljsutils_p.h"
QT_BEGIN_NAMESPACE
@@ -28,14 +29,6 @@ struct PendingBlock
bool registerActive = false;
};
-template <typename Container>
-void deduplicate(Container &container)
-{
- std::sort(container.begin(), container.end());
- auto erase = std::unique(container.begin(), container.end());
- container.erase(erase, container.end());
-}
-
template<typename ContainerA, typename ContainerB>
static bool containsAny(const ContainerA &container, const ContainerB &elements)
{
@@ -529,8 +522,8 @@ void QQmlJSOptimizations::populateBasicBlocks()
}
}
- deduplicate(block.readTypes);
- deduplicate(block.readRegisters);
+ QQmlJSUtils::deduplicate(block.readTypes);
+ QQmlJSUtils::deduplicate(block.readRegisters);
}
}
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index b32f86226e..535134072f 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -1143,12 +1143,27 @@ bool QQmlJSScope::Export::isValid() const
return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty();
}
+QDeferredFactory<QQmlJSScope>::QDeferredFactory(QQmlJSImporter *importer, const QString &filePath,
+ const TypeReader &typeReader)
+ : m_filePath(filePath),
+ m_importer(importer),
+ m_typeReader(typeReader ? typeReader
+ : [](QQmlJSImporter *importer, const QString &filePath,
+ const QSharedPointer<QQmlJSScope> &scopeToPopulate) {
+ QQmlJSTypeReader defaultTypeReader(importer, filePath);
+ defaultTypeReader(scopeToPopulate);
+ return defaultTypeReader.errors();
+ })
+{
+}
+
void QDeferredFactory<QQmlJSScope>::populate(const QSharedPointer<QQmlJSScope> &scope) const
{
scope->setOwnModuleName(m_moduleName);
- QQmlJSTypeReader typeReader(m_importer, m_filePath);
- typeReader(scope);
- m_importer->m_globalWarnings.append(typeReader.errors());
+
+ QList<QQmlJS::DiagnosticMessage> errors = m_typeReader(m_importer, m_filePath, scope);
+ m_importer->m_globalWarnings.append(errors);
+
scope->setInternalName(internalName());
QQmlJSScope::resolveEnums(scope, m_importer->builtinInternalNames());
QQmlJSScope::resolveList(scope, m_importer->builtinInternalNames().arrayType());
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index 97ec6cc004..b0bc6818a3 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -641,11 +641,13 @@ template<>
class Q_QMLCOMPILER_EXPORT QDeferredFactory<QQmlJSScope>
{
public:
+ using TypeReader = std::function<QList<QQmlJS::DiagnosticMessage>(
+ QQmlJSImporter *importer, const QString &filePath,
+ const QSharedPointer<QQmlJSScope> &scopeToPopulate)>;
QDeferredFactory() = default;
- QDeferredFactory(QQmlJSImporter *importer, const QString &filePath) :
- m_filePath(filePath), m_importer(importer)
- {}
+ QDeferredFactory(QQmlJSImporter *importer, const QString &filePath,
+ const TypeReader &typeReader = {});
bool isValid() const
{
@@ -657,6 +659,10 @@ public:
return QFileInfo(m_filePath).baseName();
}
+ QString filePath() const { return m_filePath; }
+
+ QQmlJSImporter* importer() const { return m_importer; }
+
void setIsSingleton(bool isSingleton)
{
m_isSingleton = isSingleton;
@@ -677,6 +683,7 @@ private:
QQmlJSImporter *m_importer = nullptr;
bool m_isSingleton = false;
QString m_moduleName;
+ TypeReader m_typeReader;
};
using QQmlJSExportedScope = QQmlJSScope::ExportedScope<QQmlJSScope::Ptr>;
diff --git a/src/qmlcompiler/qqmljsutils_p.h b/src/qmlcompiler/qqmljsutils_p.h
index 9eb6840f9d..c23399e9ae 100644
--- a/src/qmlcompiler/qqmljsutils_p.h
+++ b/src/qmlcompiler/qqmljsutils_p.h
@@ -21,10 +21,12 @@
#include "qqmljsscope_p.h"
#include "qqmljsmetatypes_p.h"
+#include <QtCore/qdir.h>
#include <QtCore/qstack.h>
#include <QtCore/qstring.h>
-#include <QtCore/qstringview.h>
#include <QtCore/qstringbuilder.h>
+#include <QtCore/qstringview.h>
+
#include <QtQml/private/qqmlsignalnames_p.h>
#include <private/qduplicatetracker_p.h>
@@ -200,7 +202,7 @@ struct Q_QMLCOMPILER_EXPORT QQmlJSUtils
const AliasResolutionVisitor &visitor);
template<typename QQmlJSScopePtr, typename Action>
- static bool searchBaseAndExtensionTypes(QQmlJSScopePtr type, const Action &check)
+ static bool searchBaseAndExtensionTypes(const QQmlJSScopePtr &type, const Action &check)
{
if (!type)
return false;
@@ -364,6 +366,21 @@ struct Q_QMLCOMPILER_EXPORT QQmlJSUtils
static std::variant<QString, QQmlJS::DiagnosticMessage>
sourceDirectoryPath(const QQmlJSImporter *importer, const QString &buildDirectoryPath);
+
+ template <typename Container>
+ static void deduplicate(Container &container)
+ {
+ std::sort(container.begin(), container.end());
+ auto erase = std::unique(container.begin(), container.end());
+ container.erase(erase, container.end());
+ }
+
+ static QStringList cleanPaths(QStringList &&paths)
+ {
+ for (QString &path : paths)
+ path = QDir::cleanPath(path);
+ return std::move(paths);
+ }
};
bool Q_QMLCOMPILER_EXPORT canStrictlyCompareWithVar(
diff --git a/src/qmldom/qqmldomastcreator.cpp b/src/qmldom/qqmldomastcreator.cpp
index c22a50ccfd..f33f259cc3 100644
--- a/src/qmldom/qqmldomastcreator.cpp
+++ b/src/qmldom/qqmldomastcreator.cpp
@@ -643,8 +643,101 @@ void QQmlDomAstCreator::endVisit(AST::UiPublicMember *el)
removeCurrentNode({});
}
+void QQmlDomAstCreator::endVisit(AST::FormalParameterList *list)
+{
+ endVisitForLists(list);
+}
+
+bool QQmlDomAstCreator::visit(AST::FunctionExpression *)
+{
+ ++m_nestedFunctionDepth;
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+ScriptElementVariant QQmlDomAstCreator::prepareBodyForFunction(AST::FunctionExpression *fExpression)
+{
+ Q_ASSERT(!scriptNodeStack.isEmpty() || !fExpression->body);
+
+ if (fExpression->body) {
+ if (currentScriptNodeEl().isList()) {
+ // It is more intuitive to have functions with a block as a body instead of a
+ // list.
+ auto body = std::make_shared<ScriptElements::BlockStatement>(
+ combineLocations(fExpression->lbraceToken, fExpression->rbraceToken));
+ body->setStatements(currentScriptNodeEl().takeList());
+ if (auto semanticScope = body->statements().semanticScope())
+ body->setSemanticScope(semanticScope);
+ auto result = ScriptElementVariant::fromElement(body);
+ removeCurrentScriptNode({});
+ return result;
+ } else {
+ auto result = currentScriptNodeEl().takeVariant();
+ removeCurrentScriptNode({});
+ return result;
+ }
+ Q_UNREACHABLE_RETURN({});
+ }
+
+ // for convenience purposes: insert an empty BlockStatement
+ auto body = std::make_shared<ScriptElements::BlockStatement>(
+ combineLocations(fExpression->lbraceToken, fExpression->rbraceToken));
+ return ScriptElementVariant::fromElement(body);
+}
+
+void QQmlDomAstCreator::endVisit(AST::FunctionExpression *fExpression)
+{
+ --m_nestedFunctionDepth;
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(fExpression, DomType::ScriptFunctionExpression);
+ if (fExpression->identifierToken.isValid())
+ current->addLocation(IdentifierRegion, fExpression->identifierToken);
+ if (fExpression->functionToken.isValid())
+ current->addLocation(FunctionKeywordRegion, fExpression->functionToken);
+ if (fExpression->lparenToken.isValid())
+ current->addLocation(LeftParenthesisRegion, fExpression->lparenToken);
+ if (fExpression->rparenToken.isValid())
+ current->addLocation(RightParenthesisRegion, fExpression->rparenToken);
+ if (fExpression->lbraceToken.isValid())
+ current->addLocation(LeftBraceRegion, fExpression->lbraceToken);
+ if (fExpression->rbraceToken.isValid())
+ current->addLocation(RightBraceRegion, fExpression->rbraceToken);
+ if (fExpression->typeAnnotation) {
+ current->addLocation(TypeIdentifierRegion,
+ combineLocations(fExpression->typeAnnotation->type));
+ }
+
+ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() && fExpression->body);
+ current->insertChild(Fields::body, prepareBodyForFunction(fExpression));
+
+ if (fExpression->typeAnnotation) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::returnType, currentScriptNodeEl().takeVariant());
+ scriptNodeStack.removeLast();
+ }
+ if (fExpression->formals) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ current->insertChild(Fields::parameters, currentScriptNodeEl().takeList());
+ scriptNodeStack.removeLast();
+ }
+
+ if (!fExpression->name.isEmpty())
+ current->insertValue(Fields::name, fExpression->name);
+
+ pushScriptElement(current);
+}
+
bool QQmlDomAstCreator::visit(AST::FunctionDeclaration *fDef)
{
+ // Treat nested functions as (named) lambdas instead of Qml Object methods.
+ if (m_nestedFunctionDepth > 0) {
+ return visit(static_cast<FunctionExpression *>(fDef));
+ }
+ ++m_nestedFunctionDepth;
const QStringView code(qmlFilePtr->code());
MethodInfo m;
m.name = fDef->name.toString();
@@ -756,6 +849,12 @@ static void setFormalParameterKind(ScriptElementVariant &variant)
void QQmlDomAstCreator::endVisit(AST::FunctionDeclaration *fDef)
{
+ // Treat nested functions as (named) lambdas instead of Qml Object methods.
+ if (m_nestedFunctionDepth > 1) {
+ endVisit(static_cast<FunctionExpression *>(fDef));
+ return;
+ }
+ --m_nestedFunctionDepth;
MethodInfo &m = std::get<MethodInfo>(currentNode().value);
const FileLocations::Tree bodyTree =
FileLocations::ensure(currentNodeEl().fileLocations, Path().field(Fields::body));
@@ -764,30 +863,9 @@ void QQmlDomAstCreator::endVisit(AST::FunctionDeclaration *fDef)
if (!m_enableScriptExpressions)
return;
- if (fDef->body) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
- if (currentScriptNodeEl().isList()) {
- // It is more intuitive to have functions with a block as a body instead of a
- // list.
- auto body = std::make_shared<ScriptElements::BlockStatement>(
- combineLocations(fDef->lbraceToken, fDef->rbraceToken));
- body->setStatements(currentScriptNodeEl().takeList());
- if (auto semanticScope = body->statements().semanticScope())
- body->setSemanticScope(semanticScope);
- m.body->setScriptElement(finalizeScriptExpression(
- ScriptElementVariant::fromElement(body), bodyPath, bodyTree));
- } else {
- m.body->setScriptElement(finalizeScriptExpression(
- currentScriptNodeEl().takeVariant(), bodyPath, bodyTree));
- }
- removeCurrentScriptNode({});
- } else {
- // for convenience purposes: insert an empty BlockStatement
- auto body = std::make_shared<ScriptElements::BlockStatement>(
- combineLocations(fDef->lbraceToken, fDef->rbraceToken));
- m.body->setScriptElement(finalizeScriptExpression(ScriptElementVariant::fromElement(body),
- bodyPath, bodyTree));
- }
+ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() && fDef->body);
+ m.body->setScriptElement(
+ finalizeScriptExpression(prepareBodyForFunction(fDef), bodyPath, bodyTree));
if (fDef->typeAnnotation) {
auto argLoc = FileLocations::ensure(nodeStack.last().fileLocations,
@@ -795,30 +873,29 @@ void QQmlDomAstCreator::endVisit(AST::FunctionDeclaration *fDef)
AttachedInfo::PathType::Relative);
const Path pathToReturnType = Path().field(Fields::scriptElement);
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
ScriptElementVariant variant = currentScriptNodeEl().takeVariant();
finalizeScriptExpression(variant, pathToReturnType, argLoc);
m.returnType->setScriptElement(variant);
removeCurrentScriptNode({});
}
- std::vector<FormalParameterList *> reversedInitializerExpressions;
- for (auto it = fDef->formals; it; it = it->next) {
- reversedInitializerExpressions.push_back(it);
- }
- const size_t size = reversedInitializerExpressions.size();
- for (size_t idx = size - 1; idx < size; --idx) {
- auto argLoc = FileLocations::ensure(
- nodeStack.last().fileLocations,
- Path().field(Fields::parameters).index(idx).field(Fields::value),
- AttachedInfo::PathType::Relative);
- const Path pathToArgument = Path().field(Fields::scriptElement);
-
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
- ScriptElementVariant variant = currentScriptNodeEl().takeVariant();
- setFormalParameterKind(variant);
- finalizeScriptExpression(variant, pathToArgument, argLoc);
- m.parameters[idx].value->setScriptElement(variant);
- removeCurrentScriptNode({});
+ if (fDef->formals) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ auto parameterList = scriptNodeStack.takeLast().takeList();
+ const auto parameterQList = parameterList.qList();
+ size_t size = (size_t)parameterQList.size();
+ for (size_t idx = size - 1; idx < size; --idx) {
+ auto argLoc = FileLocations::ensure(
+ nodeStack.last().fileLocations,
+ Path().field(Fields::parameters).index(idx).field(Fields::value),
+ AttachedInfo::PathType::Relative);
+ const Path pathToArgument = Path().field(Fields::scriptElement);
+
+ ScriptElementVariant variant = parameterQList[idx];
+ setFormalParameterKind(variant);
+ finalizeScriptExpression(variant, pathToArgument, argLoc);
+ m.parameters[idx].value->setScriptElement(variant);
+ }
}
// there should be no more uncollected script elements
@@ -969,7 +1046,10 @@ bool QQmlDomAstCreator::visit(AST::UiObjectBinding *el)
setBindingIdentifiers(bPathFromOwner, el->qualifiedId, bPtr);
pushEl(bPathFromOwner, *bPtr, el);
- FileLocations::addRegion(nodeStack.last().fileLocations, ColonTokenRegion, el->colonToken);
+ if (el->hasOnToken)
+ FileLocations::addRegion(nodeStack.last().fileLocations, OnTokenRegion, el->colonToken);
+ else
+ FileLocations::addRegion(nodeStack.last().fileLocations, ColonTokenRegion, el->colonToken);
FileLocations::addRegion(nodeStack.last().fileLocations, IdentifierRegion, combineLocations(el->qualifiedId));
loadAnnotations(el);
QmlObject *objValue = bPtr->objectValue();
@@ -1176,30 +1256,9 @@ void QQmlDomAstCreator::endVisit(AST::UiArrayBinding *)
removeCurrentNode(DomType::Binding);
}
-bool QQmlDomAstCreator::visit(AST::ArgumentList *list)
+void QQmlDomAstCreator::endVisit(AST::ArgumentList *list)
{
- if (!m_enableScriptExpressions)
- return false;
-
- auto currentList = makeScriptList(list);
-
- for (auto it = list; it; it = it->next) {
- Node::accept(it->expression, this);
- if (!m_enableScriptExpressions)
- return false;
-
- if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) {
- Q_SCRIPTELEMENT_DISABLE();
- return false;
- }
- currentList.append(scriptNodeStack.last().takeVariant());
- scriptNodeStack.removeLast();
- }
-
- pushScriptElement(currentList);
-
- return false; // return false because we already iterated over the children using the custom
- // iteration above
+ endVisitForLists(list);
}
bool QQmlDomAstCreator::visit(AST::UiParameterList *)
@@ -1207,65 +1266,19 @@ bool QQmlDomAstCreator::visit(AST::UiParameterList *)
return false; // do not create script node for Ui stuff
}
-bool QQmlDomAstCreator::visit(AST::PatternElementList *list)
+void QQmlDomAstCreator::endVisit(AST::PatternElementList *list)
{
- if (!m_enableScriptExpressions)
- return false;
-
- auto currentList = makeScriptList(list);
-
- for (auto it = list; it; it = it->next) {
- if (it->elision) {
- Node::accept(it->elision, this);
- if (scriptNodeStack.empty() || !scriptNodeStack.last().isList()) {
- Q_SCRIPTELEMENT_DISABLE();
- return false;
- }
- currentList.append(scriptNodeStack.last().takeList());
- scriptNodeStack.removeLast();
- }
- if (it->element) {
- Node::accept(it->element, this);
- if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) {
- Q_SCRIPTELEMENT_DISABLE();
- return false;
- }
- currentList.append(scriptNodeStack.last().takeVariant());
- scriptNodeStack.removeLast();
- }
- }
-
- pushScriptElement(currentList);
-
- return false; // return false because we already iterated over the children using the custom
- // iteration above
+ endVisitForLists<AST::PatternElementList>(list, [](AST::PatternElementList *current) {
+ int toCollect = 0;
+ toCollect += bool(current->elision);
+ toCollect += bool(current->element);
+ return toCollect;
+ });
}
-bool QQmlDomAstCreator::visit(AST::PatternPropertyList *list)
+void QQmlDomAstCreator::endVisit(AST::PatternPropertyList *list)
{
- if (!m_enableScriptExpressions)
- return false;
-
- auto currentList = makeScriptList(list);
-
- for (auto it = list; it; it = it->next) {
- if (it->property) {
- Node::accept(it->property, this);
- if (!m_enableScriptExpressions)
- return false;
- if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) {
- Q_SCRIPTELEMENT_DISABLE();
- return false;
- }
- currentList.append(scriptNodeStack.last().takeVariant());
- scriptNodeStack.removeLast();
- }
- }
-
- pushScriptElement(currentList);
-
- return false; // return false because we already iterated over the children using the custom
- // iteration above
+ endVisitForLists(list);
}
/*!
@@ -1317,7 +1330,9 @@ void QQmlDomAstCreator::endVisit(AST::UiEnumDeclaration *)
bool QQmlDomAstCreator::visit(AST::UiEnumMemberList *el)
{
- EnumItem it(el->member.toString(), el->value);
+ EnumItem it(el->member.toString(), el->value,
+ el->valueToken.isValid() ? EnumItem::ValueKind::ExplicitValue
+ : EnumItem::ValueKind::ImplicitValue);
EnumDecl &eDecl = std::get<EnumDecl>(currentNode().value);
Path itPathFromDecl = eDecl.addValue(it);
const auto map = createMap(DomType::EnumItem, itPathFromDecl, nullptr);
@@ -1456,28 +1471,9 @@ void QQmlDomAstCreator::throwRecursionDepthError()
tr("Maximum statement or expression depth exceeded in QmlDomAstCreator")));
}
-bool QQmlDomAstCreator::visit(AST::StatementList *)
-{
- if (!m_enableScriptExpressions)
- return false;
-
- return true;
-}
-
void QQmlDomAstCreator::endVisit(AST::StatementList *list)
{
- if (!m_enableScriptExpressions)
- return;
-
- auto current = makeScriptList(list);
-
- for (auto it = list; it; it = it->next) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
- current.append(scriptNodeStack.takeLast().takeVariant());
- }
-
- current.reverse();
- pushScriptElement(current);
+ endVisitForLists(list);
}
bool QQmlDomAstCreator::visit(AST::BinaryExpression *)
@@ -1495,10 +1491,10 @@ void QQmlDomAstCreator::endVisit(AST::BinaryExpression *exp)
auto current = makeScriptElement<ScriptElements::BinaryExpression>(exp);
current->addLocation(OperatorTokenRegion, exp->operatorToken);
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setRight(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setLeft(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
@@ -1521,7 +1517,7 @@ void QQmlDomAstCreator::endVisit(AST::Block *block)
auto current = makeScriptElement<ScriptElements::BlockStatement>(block);
if (block->statements) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->setStatements(currentScriptNodeEl().takeList());
removeCurrentScriptNode(DomType::List);
}
@@ -1552,25 +1548,25 @@ void QQmlDomAstCreator::endVisit(AST::ForStatement *forStatement)
current->addLocation(FileLocationRegion::RightParenthesisRegion, forStatement->rparenToken);
if (forStatement->statement) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setBody(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode(std::nullopt);
}
if (forStatement->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setExpression(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode(std::nullopt);
}
if (forStatement->condition) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setCondition(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode(std::nullopt);
}
if (forStatement->declarations) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
auto variableDeclaration = makeGenericScriptElement(forStatement->declarations,
DomType::ScriptVariableDeclaration);
@@ -1581,10 +1577,16 @@ void QQmlDomAstCreator::endVisit(AST::ForStatement *forStatement)
removeCurrentScriptNode({});
current->setDeclarations(ScriptElementVariant::fromElement(variableDeclaration));
+
+ if (auto pe = forStatement->declarations->declaration;
+ pe && pe->declarationKindToken.isValid()) {
+ current->addLocation(FileLocationRegion::TypeIdentifierRegion,
+ pe->declarationKindToken);
+ }
}
if (forStatement->initialiser) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setInitializer(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode(std::nullopt);
}
@@ -1704,30 +1706,33 @@ bool QQmlDomAstCreator::visit(AST::ComputedPropertyName *)
return true;
}
-bool QQmlDomAstCreator::visit(AST::VariableDeclarationList *list)
+template<typename T>
+void QQmlDomAstCreator::endVisitForLists(T *list,
+ const std::function<int(T *)> &scriptElementsPerEntry)
{
if (!m_enableScriptExpressions)
- return false;
-
- auto currentList = makeScriptList(list);
+ return;
+ auto current = makeScriptList(list);
for (auto it = list; it; it = it->next) {
- if (it->declaration) {
- Node::accept(it->declaration, this);
- if (!m_enableScriptExpressions)
- return false;
- if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) {
- Q_SCRIPTELEMENT_DISABLE();
- return false;
- }
- currentList.append(scriptNodeStack.last().takeVariant());
- scriptNodeStack.removeLast();
+ const int entriesToCollect = scriptElementsPerEntry ? scriptElementsPerEntry(it) : 1;
+ for (int i = 0; i < entriesToCollect; ++i) {
+ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ auto last = scriptNodeStack.takeLast();
+ if (last.isList())
+ current.append(last.takeList());
+ else
+ current.append(last.takeVariant());
}
}
- pushScriptElement(currentList);
- return false; // return false because we already iterated over the children using the custom
- // iteration above
+ current.reverse();
+ pushScriptElement(current);
+}
+
+void QQmlDomAstCreator::endVisit(AST::VariableDeclarationList *list)
+{
+ endVisitForLists(list);
}
bool QQmlDomAstCreator::visit(AST::Elision *list)
@@ -1774,17 +1779,17 @@ void QQmlDomAstCreator::endVisitHelper(
current->insertChild(Fields::identifier, ScriptElementVariant::fromElement(identifier));
}
if (pe->initializer) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::initializer, scriptNodeStack.last().takeVariant());
scriptNodeStack.removeLast();
}
if (pe->typeAnnotation) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::type, scriptNodeStack.last().takeVariant());
scriptNodeStack.removeLast();
}
if (pe->bindingTarget) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::bindingElement, scriptNodeStack.last().takeVariant());
scriptNodeStack.removeLast();
}
@@ -1821,20 +1826,21 @@ void QQmlDomAstCreator::endVisit(AST::IfStatement *ifStatement)
current->addLocation(LeftParenthesisRegion, ifStatement->lparenToken);
current->addLocation(RightParenthesisRegion, ifStatement->rparenToken);
current->addLocation(ElseKeywordRegion, ifStatement->elseToken);
+ current->addLocation(IfKeywordRegion, ifStatement->ifToken);
if (ifStatement->ko) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setAlternative(scriptNodeStack.last().takeVariant());
scriptNodeStack.removeLast();
}
if (ifStatement->ok) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setConsequence(scriptNodeStack.last().takeVariant());
scriptNodeStack.removeLast();
}
if (ifStatement->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setCondition(scriptNodeStack.last().takeVariant());
scriptNodeStack.removeLast();
}
@@ -1859,7 +1865,7 @@ void QQmlDomAstCreator::endVisit(AST::ReturnStatement *returnStatement)
current->addLocation(ReturnKeywordRegion, returnStatement->returnToken);
if (returnStatement->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setExpression(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -1867,6 +1873,31 @@ void QQmlDomAstCreator::endVisit(AST::ReturnStatement *returnStatement)
pushScriptElement(current);
}
+bool QQmlDomAstCreator::visit(AST::YieldExpression *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::YieldExpression *yExpression)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(yExpression, DomType::ScriptYieldExpression);
+ current->addLocation(YieldKeywordRegion, yExpression->yieldToken);
+
+ if (yExpression->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
bool QQmlDomAstCreator::visit(AST::FieldMemberExpression *)
{
if (!m_enableScriptExpressions)
@@ -1885,7 +1916,7 @@ void QQmlDomAstCreator::endVisit(AST::FieldMemberExpression *expression)
current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->dotToken);
if (expression->base) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setLeft(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -1916,7 +1947,7 @@ void QQmlDomAstCreator::endVisit(AST::ArrayMemberExpression *expression)
current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->lbracketToken);
if (expression->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
// if scriptNodeStack.last() is fieldmember expression, add expression to it instead of
// creating new one
current->setRight(currentScriptNodeEl().takeVariant());
@@ -1924,7 +1955,7 @@ void QQmlDomAstCreator::endVisit(AST::ArrayMemberExpression *expression)
}
if (expression->base) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setLeft(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -1950,7 +1981,7 @@ void QQmlDomAstCreator::endVisit(AST::CallExpression *exp)
current->addLocation(RightParenthesisRegion, exp->rparenToken);
if (exp->arguments) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->insertChild(Fields::arguments, currentScriptNodeEl().takeList());
removeCurrentScriptNode({});
} else {
@@ -1960,7 +1991,7 @@ void QQmlDomAstCreator::endVisit(AST::CallExpression *exp)
}
if (exp->base) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::callee, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -1984,7 +2015,7 @@ void QQmlDomAstCreator::endVisit(AST::ArrayPattern *exp)
auto current = makeGenericScriptElement(exp, DomType::ScriptArray);
if (exp->elements) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
ScriptElements::ScriptList list = currentScriptNodeEl().takeList();
list.replaceKindForGenericChildren(DomType::ScriptPattern, DomType::ScriptArrayEntry);
current->insertChild(Fields::elements, std::move(list));
@@ -2015,7 +2046,7 @@ void QQmlDomAstCreator::endVisit(AST::ObjectPattern *exp)
auto current = makeGenericScriptElement(exp, DomType::ScriptObject);
if (exp->properties) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->insertChild(Fields::properties, currentScriptNodeEl().takeList());
removeCurrentScriptNode({});
} else {
@@ -2050,7 +2081,7 @@ void QQmlDomAstCreator::endVisit(AST::PatternProperty *exp)
return;
if (exp->name) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::name, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2072,9 +2103,10 @@ void QQmlDomAstCreator::endVisit(AST::VariableStatement *statement)
return;
auto current = makeGenericScriptElement(statement, DomType::ScriptVariableDeclaration);
+ current->addLocation(FileLocationRegion::TypeIdentifierRegion, statement->declarationKindToken);
if (statement->declarations) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
ScriptElements::ScriptList list = currentScriptNodeEl().takeList();
list.replaceKindForGenericChildren(DomType::ScriptPattern,
@@ -2105,10 +2137,12 @@ void QQmlDomAstCreator::endVisit(AST::Type *exp)
if (exp->typeArgument) {
current->insertChild(Fields::typeArgumentName,
fieldMemberExpressionForQualifiedId(exp->typeArgument));
+ current->addLocation(FileLocationRegion::IdentifierRegion, combineLocations(exp->typeArgument));
}
if (exp->typeId) {
current->insertChild(Fields::typeName, fieldMemberExpressionForQualifiedId(exp->typeId));
+ current->addLocation(FileLocationRegion::TypeIdentifierRegion, combineLocations(exp->typeId));
}
pushScriptElement(current);
@@ -2132,7 +2166,7 @@ void QQmlDomAstCreator::endVisit(AST::DefaultClause *exp)
current->addLocation(ColonTokenRegion, exp->colonToken);
if (exp->statements) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
removeCurrentScriptNode({});
}
@@ -2158,13 +2192,13 @@ void QQmlDomAstCreator::endVisit(AST::CaseClause *exp)
current->addLocation(FileLocationRegion::ColonTokenRegion, exp->colonToken);
if (exp->statements) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
removeCurrentScriptNode({});
}
if (exp->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2188,7 +2222,7 @@ void QQmlDomAstCreator::endVisit(AST::CaseClauses *list)
auto current = makeScriptList(list);
for (auto it = list; it; it = it->next) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current.append(scriptNodeStack.takeLast().takeVariant());
}
@@ -2214,19 +2248,19 @@ void QQmlDomAstCreator::endVisit(AST::CaseBlock *exp)
current->addLocation(FileLocationRegion::RightBraceRegion, exp->rbraceToken);
if (exp->moreClauses) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->insertChild(Fields::moreCaseClauses, currentScriptNodeEl().takeList());
removeCurrentScriptNode({});
}
if (exp->defaultClause) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::defaultClause, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (exp->clauses) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->insertChild(Fields::caseClauses, currentScriptNodeEl().takeList());
removeCurrentScriptNode({});
}
@@ -2247,16 +2281,17 @@ void QQmlDomAstCreator::endVisit(AST::SwitchStatement *exp)
return;
auto current = makeGenericScriptElement(exp, DomType::ScriptSwitchStatement);
+ current->addLocation(FileLocationRegion::SwitchKeywordRegion, exp->switchToken);
current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
if (exp->block) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::caseBlock, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (exp->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2283,13 +2318,13 @@ void QQmlDomAstCreator::endVisit(AST::WhileStatement *exp)
current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
if (exp->statement) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (exp->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2317,13 +2352,13 @@ void QQmlDomAstCreator::endVisit(AST::DoWhileStatement *exp)
current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
if (exp->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (exp->statement) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2345,25 +2380,32 @@ void QQmlDomAstCreator::endVisit(AST::ForEachStatement *exp)
return;
auto current = makeGenericScriptElement(exp, DomType::ScriptForEachStatement);
+ current->addLocation(FileLocationRegion::ForKeywordRegion, exp->forToken);
current->addLocation(FileLocationRegion::InOfTokenRegion, exp->inOfToken);
current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
if (exp->statement) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (exp->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (exp->lhs) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::bindingElement, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
+
+ if (auto pe = AST::cast<PatternElement *>(exp->lhs);
+ pe && pe->declarationKindToken.isValid()) {
+ current->addLocation(FileLocationRegion::TypeIdentifierRegion,
+ pe->declarationKindToken);
+ }
}
pushScriptElement(current);
@@ -2408,7 +2450,7 @@ void QQmlDomAstCreator::endVisit(AST::TryStatement *statement)
if (auto exp = statement->finallyExpression) {
current->addLocation(FileLocationRegion::FinallyKeywordRegion, exp->finallyToken);
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::finallyBlock, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2418,16 +2460,16 @@ void QQmlDomAstCreator::endVisit(AST::TryStatement *statement)
current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::catchBlock, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::catchParameter, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (statement->statement) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::block, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2471,7 +2513,7 @@ void QQmlDomAstCreator::endVisit(AST::ThrowStatement *statement)
current->addLocation(FileLocationRegion::ThrowKeywordRegion, statement->throwToken);
if (statement->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2498,7 +2540,7 @@ void QQmlDomAstCreator::endVisit(AST::LabelledStatement *statement)
if (statement->statement) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::statement, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2545,13 +2587,13 @@ void QQmlDomAstCreator::endVisit(AST::Expression *commaExpression)
current->addLocation(OperatorTokenRegion, commaExpression->commaToken);
if (commaExpression->right) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setRight(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (commaExpression->left) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setLeft(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2574,19 +2616,19 @@ void QQmlDomAstCreator::endVisit(AST::ConditionalExpression *expression)
current->addLocation(FileLocationRegion::ColonTokenRegion, expression->colonToken);
if (expression->ko) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::alternative, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (expression->ok) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::consequence, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (expression->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::condition, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2640,7 +2682,7 @@ QQmlDomAstCreator::makeUnaryExpression(AST::Node *expression, QQmlJS::SourceLoca
current->addLocation(FileLocationRegion::OperatorTokenRegion, operatorToken);
if (hasExpression) {
- if (scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()) {
+ if (!stackHasScriptVariant()) {
Q_SCRIPTELEMENT_DISABLE();
return {};
}
@@ -2861,7 +2903,7 @@ void QQmlDomAstCreator::endVisit(AST::NestedExpression *expression)
current->addLocation(FileLocationRegion::RightParenthesisRegion, expression->rparenToken);
if (expression->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2949,6 +2991,30 @@ void QQmlDomAstCreatorWithQQmlJSScope::setScopeInDomAfterEndvisit()
case DomType::List:
m_domCreator.currentScriptNodeEl().setSemanticScope(scope);
break;
+ case DomType::ScriptFunctionExpression: {
+ // Put the body's scope into the function expression: function expressions will contain
+ // their parents scope instead of their own without this
+ auto element = m_domCreator.currentScriptNodeEl().value;
+ auto scriptElementVariant = std::get_if<ScriptElementVariant>(&element);
+ if (!scriptElementVariant || !scriptElementVariant->data())
+ break;
+ scriptElementVariant->visit([](auto &&e) {
+ using U = std::remove_cv_t<std::remove_reference_t<decltype(e)>>;
+ if (e->kind() != DomType::ScriptFunctionExpression)
+ return;
+
+ if constexpr (std::is_same_v<U,
+ ScriptElement::PointerType<
+ ScriptElements::GenericScriptElement>>) {
+ if (auto bodyPtr = e->elementChild(Fields::body)) {
+ const auto bodyScope = bodyPtr.base()->semanticScope();
+ e->setSemanticScope(bodyScope);
+ }
+ }
+ });
+ break;
+ }
+
// TODO: find which script elements also have a scope and implement them here
default:
break;
@@ -2992,11 +3058,13 @@ void QQmlDomAstCreatorWithQQmlJSScope::setScopeInDomBeforeEndvisit()
// property definition has a binding, like `property int i: 45` for
// example), then the property definition scope is the parent of the current
// scope.
- e.setSemanticScope(scope->scopeType() == QQmlSA::ScopeType::JSFunctionScope
+ const bool usePropertyDefinitionScopeInsteadOfTheBindingScope =
+ scope->scopeType() == QQmlSA::ScopeType::JSFunctionScope
+ && scope->parentScope()
+ && scope->parentScope()->scopeType() == QQmlSA::ScopeType::QMLScope;
+ e.setSemanticScope(usePropertyDefinitionScopeInsteadOfTheBindingScope
? scope->parentScope()
: scope);
- Q_ASSERT(e.semanticScope()
- && e.semanticScope()->scopeType() == QQmlSA::ScopeType::QMLScope);
}
},
m_domCreator.currentNodeEl(1).item.value);
diff --git a/src/qmldom/qqmldomastcreator_p.h b/src/qmldom/qqmldomastcreator_p.h
index 8176721d7e..8a050b4c2d 100644
--- a/src/qmldom/qqmldomastcreator_p.h
+++ b/src/qmldom/qqmldomastcreator_p.h
@@ -135,6 +135,7 @@ private:
QList<ScriptStackElement> scriptNodeStack;
QVector<int> arrayBindingLevels;
FileLocations::Tree rootMap;
+ int m_nestedFunctionDepth = 0;
bool m_enableScriptExpressions = false;
bool m_loadFileLazily = false;
@@ -321,6 +322,13 @@ public:
bool visit(AST::UiPublicMember *el) override;
void endVisit(AST::UiPublicMember *el) override;
+private:
+ ScriptElementVariant prepareBodyForFunction(AST::FunctionExpression *fExpression);
+
+public:
+ bool visit(AST::FunctionExpression *el) override;
+ void endVisit(AST::FunctionExpression *) override;
+
bool visit(AST::FunctionDeclaration *el) override;
void endVisit(AST::FunctionDeclaration *) override;
@@ -364,6 +372,9 @@ public:
bool visit(AST::Block *block) override;
void endVisit(AST::Block *) override;
+ bool visit(AST::YieldExpression *block) override;
+ void endVisit(AST::YieldExpression *) override;
+
bool visit(AST::ReturnStatement *block) override;
void endVisit(AST::ReturnStatement *) override;
@@ -497,17 +508,20 @@ public:
bool visit(AST::NestedExpression *) override;
void endVisit(AST::NestedExpression *) override;
- // lists of stuff whose children do not need a qqmljsscope: visitation order can be custom
- bool visit(AST::ArgumentList *) override;
+
+ // lists of stuff whose children don't need a qqmljsscope: visitation order can be custom
bool visit(AST::UiParameterList *) override;
- bool visit(AST::PatternElementList *) override;
- bool visit(AST::PatternPropertyList *) override;
- bool visit(AST::VariableDeclarationList *vdl) override;
bool visit(AST::Elision *elision) override;
+
// lists of stuff whose children need a qqmljsscope: visitation order cannot be custom
- bool visit(AST::StatementList *list) override;
void endVisit(AST::StatementList *list) override;
+ void endVisit(AST::VariableDeclarationList *vdl) override;
+ void endVisit(AST::ArgumentList *) override;
+ void endVisit(AST::PatternElementList *) override;
+ void endVisit(AST::PatternPropertyList *) override;
+ void endVisit(AST::FormalParameterList *el) override;
+
// literals and ids
bool visit(AST::IdentifierExpression *expression) override;
@@ -524,6 +538,19 @@ public:
void throwRecursionDepthError() override;
+ bool stackHasScriptVariant() const
+ {
+ return !scriptNodeStack.isEmpty() && !scriptNodeStack.last().isList();
+ }
+ bool stackHasScriptList() const
+ {
+ return !scriptNodeStack.isEmpty() && scriptNodeStack.last().isList();
+ }
+
+private:
+ template<typename T>
+ void endVisitForLists(T *list, const std::function<int(T *)> &scriptElementsPerEntry = {});
+
public:
friend class QQmlDomAstCreatorWithQQmlJSScope;
};
@@ -567,8 +594,9 @@ private:
template<typename U, typename... V>
using IsInList = std::disjunction<std::is_same<U, V>...>;
template<typename U>
- using RequiresCustomIteration = IsInList<U, AST::PatternElementList, AST::PatternPropertyList,
- AST::FormalParameterList>;
+ using RequiresCustomIteration =
+ IsInList<U, AST::PatternElementList, AST::PatternPropertyList, AST::FormalParameterList,
+ AST::VariableDeclarationList>;
enum VisitorKind : bool { DomCreator, ScopeCreator };
/*! \internal
@@ -592,7 +620,7 @@ private:
void customListIteration(T *t)
{
static_assert(RequiresCustomIteration<T>::value);
- for (auto it = t; it; it = it->next) {
+ for (T* it = t; it; it = it->next) {
if constexpr (std::is_same_v<T, AST::PatternElementList>) {
AST::Node::accept(it->elision, this);
AST::Node::accept(it->element, this);
@@ -600,6 +628,13 @@ private:
AST::Node::accept(it->property, this);
} else if constexpr (std::is_same_v<T, AST::FormalParameterList>) {
AST::Node::accept(it->element, this);
+ } else if constexpr (std::is_same_v<T, AST::VariableDeclarationList>) {
+ AST::Node::accept(it->declaration, this);
+ } else if constexpr (std::is_same_v<T, AST::ArgumentList>) {
+ AST::Node::accept(it->expression, this);
+ } else if constexpr (std::is_same_v<T, AST::PatternElementList>) {
+ AST::Node::accept(it->elision, this);
+ AST::Node::accept(it->element, this);
} else {
Q_UNREACHABLE();
}
diff --git a/src/qmldom/qqmldomcomments.cpp b/src/qmldom/qqmldomcomments.cpp
index 2d3a8cde70..308467b99b 100644
--- a/src/qmldom/qqmldomcomments.cpp
+++ b/src/qmldom/qqmldomcomments.cpp
@@ -65,7 +65,8 @@ Comments store a string (rawComment) with comment characters (//,..) and spaces.
Sometime one wants just the comment, the commentcharacters, the space before the comment,....
CommentInfo gets such a raw comment string and makes the various pieces available
*/
-CommentInfo::CommentInfo(QStringView rawComment) : rawComment(rawComment)
+CommentInfo::CommentInfo(QStringView rawComment, QQmlJS::SourceLocation loc)
+ : rawComment(rawComment), commentLocation(loc)
{
commentBegin = 0;
while (commentBegin < quint32(rawComment.size()) && rawComment.at(commentBegin).isSpace()) {
@@ -97,6 +98,7 @@ CommentInfo::CommentInfo(QStringView rawComment) : rawComment(rawComment)
warnings.append(tr("Unexpected comment start %1").arg(commentStartStr));
break;
}
+
commentEnd = commentBegin + commentStartStr.size();
quint32 rawEnd = quint32(rawComment.size());
commentContentEnd = commentContentBegin = commentEnd;
@@ -155,6 +157,11 @@ CommentInfo::CommentInfo(QStringView rawComment) : rawComment(rawComment)
.arg(i));
}
}
+
+ // Post process comment source location
+ commentLocation.offset -= commentStartStr.size();
+ commentLocation.startColumn -= commentStartStr.size();
+ commentLocation.length = commentEnd - commentBegin;
}
/*!
diff --git a/src/qmldom/qqmldomcomments_p.h b/src/qmldom/qqmldomcomments_p.h
index 732a74162a..f8fe46c098 100644
--- a/src/qmldom/qqmldomcomments_p.h
+++ b/src/qmldom/qqmldomcomments_p.h
@@ -38,7 +38,7 @@ class QMLDOM_EXPORT CommentInfo
{
Q_DECLARE_TR_FUNCTIONS(CommentInfo)
public:
- CommentInfo(QStringView);
+ CommentInfo(QStringView, QQmlJS::SourceLocation loc);
QStringView preWhitespace() const { return rawComment.mid(0, commentBegin); }
@@ -54,6 +54,10 @@ public:
return rawComment.mid(commentEnd, rawComment.size() - commentEnd);
}
+ // Comment source location populated during lexing doesn't include start strings // or /*
+ // Returns the location starting from // or /*
+ QQmlJS::SourceLocation sourceLocation() const { return commentLocation; }
+
quint32 commentBegin = 0;
quint32 commentEnd = 0;
quint32 commentContentBegin = 0;
@@ -65,6 +69,7 @@ public:
int nContentNewlines = 0;
QStringView rawComment;
QStringList warnings;
+ QQmlJS::SourceLocation commentLocation;
};
class QMLDOM_EXPORT Comment
@@ -90,7 +95,7 @@ public:
int newlinesBefore() const { return m_newlinesBefore; }
void setNewlinesBefore(int n) { m_newlinesBefore = n; }
QStringView rawComment() const { return m_comment; }
- CommentInfo info() const { return CommentInfo(m_comment); }
+ CommentInfo info() const { return CommentInfo(m_comment, m_location); }
void write(OutWriter &lw, SourceLocation *commentLocation = nullptr) const;
CommentType type() const { return m_type; }
@@ -101,8 +106,6 @@ public:
}
friend bool operator!=(const Comment &c1, const Comment &c2) { return !(c1 == c2); }
- QQmlJS::SourceLocation sourceLocation() const { return m_location; };
-
private:
QStringView m_comment;
QQmlJS::SourceLocation m_location;
diff --git a/src/qmldom/qqmldomconstants_p.h b/src/qmldom/qqmldomconstants_p.h
index 1ca9389546..ac5f8f67c4 100644
--- a/src/qmldom/qqmldomconstants_p.h
+++ b/src/qmldom/qqmldomconstants_p.h
@@ -227,6 +227,8 @@ enum class DomType {
ScriptConditionalExpression,
ScriptEmptyStatement,
ScriptParenthesizedExpression,
+ ScriptFunctionExpression,
+ ScriptYieldExpression,
ScriptElementStop, // marker to check if a DomType is a scriptelement or not
};
@@ -364,6 +366,7 @@ enum FileLocationRegion : int {
IdNameRegion,
IdTokenRegion,
IdentifierRegion,
+ IfKeywordRegion,
ImportTokenRegion,
ImportUriRegion,
InOfTokenRegion,
@@ -387,11 +390,13 @@ enum FileLocationRegion : int {
SecondSemicolonRegion,
SemicolonTokenRegion,
SignalKeywordRegion,
+ SwitchKeywordRegion,
ThrowKeywordRegion,
TryKeywordRegion,
TypeIdentifierRegion,
VersionRegion,
WhileKeywordRegion,
+ YieldKeywordRegion,
};
Q_ENUM_NS(FileLocationRegion);
diff --git a/src/qmldom/qqmldomelements.cpp b/src/qmldom/qqmldomelements.cpp
index 0fe5c3eb36..348984172f 100644
--- a/src/qmldom/qqmldomelements.cpp
+++ b/src/qmldom/qqmldomelements.cpp
@@ -2017,23 +2017,12 @@ void EnumItem::writeOut(const DomItem &self, OutWriter &ow) const
{
ow.ensureNewline();
ow.writeRegion(IdentifierRegion, name());
- bool hasDefaultValue = false;
index_type myIndex = self.pathFromOwner().last().headIndex();
- if (myIndex == 0)
- hasDefaultValue = value() == 0;
- else if (myIndex > 0)
- hasDefaultValue = value()
- == self.container()
- .index(myIndex - 1)
- .field(Fields::value)
- .value()
- .toDouble(value())
- + 1;
- if (!hasDefaultValue) {
+ if (m_valueKind == ValueKind::ExplicitValue) {
QString v = QString::number(value(), 'f', 0);
if (abs(value() - v.toDouble()) > 1.e-10)
v = QString::number(value());
- ow.space().writeRegion(EqualTokenRegion).space().writeRegion(PragmaValuesRegion, v);
+ ow.space().writeRegion(EqualTokenRegion).space().writeRegion(EnumValueRegion, v);
}
if (myIndex >= 0 && self.container().indexes() != myIndex + 1)
ow.writeRegion(CommaTokenRegion);
diff --git a/src/qmldom/qqmldomelements_p.h b/src/qmldom/qqmldomelements_p.h
index db57da7bb2..95cddbbc32 100644
--- a/src/qmldom/qqmldomelements_p.h
+++ b/src/qmldom/qqmldomelements_p.h
@@ -780,8 +780,14 @@ class QMLDOM_EXPORT EnumItem
{
public:
constexpr static DomType kindValue = DomType::EnumItem;
-
- EnumItem(const QString &name = QString(), int value = 0) : m_name(name), m_value(value) { }
+ enum class ValueKind : quint8 {
+ ImplicitValue,
+ ExplicitValue
+ };
+ EnumItem(const QString &name = QString(), int value = 0, ValueKind valueKind = ValueKind::ImplicitValue)
+ : m_name(name), m_value(value), m_valueKind(valueKind)
+ {
+ }
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const;
@@ -794,6 +800,7 @@ public:
private:
QString m_name;
double m_value;
+ ValueKind m_valueKind;
RegionComments m_comments;
};
diff --git a/src/qmldom/qqmldomexternalitems_p.h b/src/qmldom/qqmldomexternalitems_p.h
index 1aa9d765cb..97328b40de 100644
--- a/src/qmldom/qqmldomexternalitems_p.h
+++ b/src/qmldom/qqmldomexternalitems_p.h
@@ -423,6 +423,11 @@ public:
DomCreationOptions creationOptions() const { return lazyMembers().m_creationOptions; }
+ QQmlJSScope::ConstPtr handleForPopulation() const
+ {
+ return m_handleForPopulation;
+ }
+
void setHandleForPopulation(const QQmlJSScope::ConstPtr &scope)
{
m_handleForPopulation = scope;
diff --git a/src/qmldom/qqmldomoutwriter.cpp b/src/qmldom/qqmldomoutwriter.cpp
index 30b75e1155..bcfc8ace69 100644
--- a/src/qmldom/qqmldomoutwriter.cpp
+++ b/src/qmldom/qqmldomoutwriter.cpp
@@ -239,7 +239,15 @@ OutWriter &OutWriter::writeRegion(FileLocationRegion region)
case SemicolonTokenRegion:
codeForRegion = u";"_s;
break;
-
+ case IfKeywordRegion:
+ codeForRegion = u"if"_s;
+ break;
+ case SwitchKeywordRegion:
+ codeForRegion = u"switch"_s;
+ break;
+ case YieldKeywordRegion:
+ codeForRegion = u"yield"_s;
+ break;
// not keywords:
case ImportUriRegion:
case IdNameRegion:
diff --git a/src/qmldom/qqmldomreformatter.cpp b/src/qmldom/qqmldomreformatter.cpp
index 5001154027..3093a3d4da 100644
--- a/src/qmldom/qqmldomreformatter.cpp
+++ b/src/qmldom/qqmldomreformatter.cpp
@@ -60,23 +60,6 @@ bool ScriptFormatter::acceptBlockOrIndented(Node *ast, bool finishWithSpaceOrNew
}
}
-void ScriptFormatter::outputScope(VariableScope scope)
-{
- switch (scope) {
- case VariableScope::Const:
- out("const ");
- break;
- case VariableScope::Let:
- out("let ");
- break;
- case VariableScope::Var:
- out("var ");
- break;
- default:
- break;
- }
-}
-
bool ScriptFormatter::visit(ThisExpression *ast)
{
out(ast->thisToken);
@@ -476,9 +459,6 @@ bool ScriptFormatter::visit(VariableStatement *ast)
bool ScriptFormatter::visit(PatternElement *ast)
{
- if (ast->isForDeclaration) {
- outputScope(ast->scope);
- }
switch (ast->type) {
case PatternElement::Literal:
case PatternElement::Method:
@@ -565,8 +545,13 @@ bool ScriptFormatter::visit(ForStatement *ast)
if (ast->initialiser) {
accept(ast->initialiser);
} else if (ast->declarations) {
- outputScope(ast->declarations->declaration->scope);
- accept(ast->declarations);
+ if (auto pe = ast->declarations->declaration) {
+ out(pe->declarationKindToken);
+ out(" ");
+ }
+ for (VariableDeclarationList *it = ast->declarations; it; it = it->next) {
+ accept(it->declaration);
+ }
}
out("; "); // ast->firstSemicolonToken
accept(ast->condition);
@@ -582,6 +567,10 @@ bool ScriptFormatter::visit(ForEachStatement *ast)
out(ast->forToken);
out(" ");
out(ast->lparenToken);
+ if (auto pe = AST::cast<PatternElement *>(ast->lhs)) {
+ out(pe->declarationKindToken);
+ out(" ");
+ }
accept(ast->lhs);
out(" ");
out(ast->inOfToken);
@@ -629,6 +618,19 @@ bool ScriptFormatter::visit(ReturnStatement *ast)
return false;
}
+bool ScriptFormatter::visit(YieldExpression *ast)
+{
+ out(ast->yieldToken);
+ if (ast->isYieldStar)
+ out("*");
+ if (ast->expression) {
+ if (ast->yieldToken.isValid())
+ out(" ");
+ accept(ast->expression);
+ }
+ return false;
+}
+
bool ScriptFormatter::visit(ThrowStatement *ast)
{
out(ast->throwToken);
diff --git a/src/qmldom/qqmldomreformatter_p.h b/src/qmldom/qqmldomreformatter_p.h
index 565d021822..48e2c63881 100644
--- a/src/qmldom/qqmldomreformatter_p.h
+++ b/src/qmldom/qqmldomreformatter_p.h
@@ -52,8 +52,6 @@ protected:
void lnAcceptIndented(AST::Node *node);
bool acceptBlockOrIndented(AST::Node *ast, bool finishWithSpaceOrNewline = false);
- void outputScope(AST::VariableScope scope);
-
bool preVisit(AST::Node *n) override;
void postVisit(AST::Node *n) override;
@@ -136,6 +134,7 @@ protected:
bool visit(AST::BreakStatement *ast) override;
bool visit(AST::ReturnStatement *ast) override;
+ bool visit(AST::YieldExpression *ast) override;
bool visit(AST::ThrowStatement *ast) override;
bool visit(AST::WithStatement *ast) override;
diff --git a/src/qmldom/qqmldomscriptelements.cpp b/src/qmldom/qqmldomscriptelements.cpp
index 4bde2abd09..c0a48e0ce3 100644
--- a/src/qmldom/qqmldomscriptelements.cpp
+++ b/src/qmldom/qqmldomscriptelements.cpp
@@ -108,6 +108,9 @@ bool GenericScriptElement::iterateDirectSubpaths(const DomItem &self, DirectVisi
[&self, &visitor, &it](auto &&e) { return wrap(self, visitor, it->first, e); },
it->second);
}
+ for (auto it = m_values.begin(); it != m_values.end(); ++it) {
+ cont &= self.dvValueField(visitor, it->first, it->second);
+ }
return cont;
}
diff --git a/src/qmldom/qqmldomscriptelements_p.h b/src/qmldom/qqmldomscriptelements_p.h
index b319e7e88f..98d863f14e 100644
--- a/src/qmldom/qqmldomscriptelements_p.h
+++ b/src/qmldom/qqmldomscriptelements_p.h
@@ -16,6 +16,7 @@
//
#include "qqmldomitem_p.h"
+#include "qqmldomelements_p.h"
#include "qqmldomattachedinfo_p.h"
#include "qqmldompath_p.h"
#include <algorithm>
@@ -181,6 +182,21 @@ public:
return m_children.insert(std::make_pair(name, v));
}
+ ScriptElementVariant elementChild(const QQmlJS::Dom::FieldType &field)
+ {
+ auto it = m_children.find(field);
+ if (it == m_children.end())
+ return {};
+ if (!std::holds_alternative<ScriptElementVariant>(it->second))
+ return {};
+ return std::get<ScriptElementVariant>(it->second);
+ }
+
+ void insertValue(QStringView name, const QCborValue &v)
+ {
+ m_values.insert(std::make_pair(name, v));
+ }
+
private:
/*!
\internal
@@ -189,6 +205,8 @@ private:
a sorted map to always iterate the children in the same order.
*/
std::map<QQmlJS::Dom::FieldType, VariantT> m_children;
+ // value fields
+ std::map<QQmlJS::Dom::FieldType, QCborValue> m_values;
DomType m_kind = DomType::Empty;
};
diff --git a/src/qmldom/qqmldomtop.cpp b/src/qmldom/qqmldomtop.cpp
index 8ae836b0a2..ae2254e66b 100644
--- a/src/qmldom/qqmldomtop.cpp
+++ b/src/qmldom/qqmldomtop.cpp
@@ -1825,44 +1825,19 @@ only works after the constructor call finished.
*/
DomEnvironment::SemanticAnalysis &DomEnvironment::semanticAnalysis()
{
+ // QTBUG-124799: do not create a SemanticAnalysis in a temporary DomEnvironment, and use the one
+ // from the base environment instead.
+ if (m_base) {
+ auto &result = m_base->semanticAnalysis();
+ result.setLoadPaths(m_loadPaths);
+ return result;
+ }
+
if (m_semanticAnalysis)
return *m_semanticAnalysis;
Q_ASSERT(domCreationOptions().testFlag(DomCreationOption::WithSemanticAnalysis));
-
m_semanticAnalysis = SemanticAnalysis(m_loadPaths);
- const auto &importer = m_semanticAnalysis->m_importer;
-
- importer->setImportVisitor([self = weak_from_this(), base = m_base](
- QQmlJS::AST::Node *rootNode, QQmlJSImporter *importer,
- const QQmlJSImporter::ImportVisitorPrerequisites &p) {
- Q_UNUSED(rootNode);
- Q_UNUSED(importer);
-
- // support the "commitToBase" workflow, which does changes in a temporary
- // DomEnvironment. if the current DomEnvironment is temporary (e.g. the weak pointer is
- // null), then we assume that the current DomEnvironment was committed to base and then
- // destructed. Use the base DomEnvironment instead.
- std::shared_ptr<DomEnvironment> envPtr;
- if (auto ptr = self.lock()) {
- envPtr = ptr;
- } else {
- envPtr = base;
- }
- // populate QML File if from implicit import directory
- // use the version in DomEnvironment and do *not* load from disk.
- auto it = envPtr->m_qmlFileWithPath.constFind(p.m_logger->fileName());
- if (it == envPtr->m_qmlFileWithPath.constEnd()) {
- qCDebug(domLog) << "Import visitor tried to lazily load file \""
- << p.m_logger->fileName()
- << "\", but that file was not found in the DomEnvironment. Was this "
- "file not discovered by the Dom's dependency loading mechanism?";
- return;
- }
- const DomItem qmlFile = it.value()->currentItem(DomItem(envPtr));
- envPtr->populateFromQmlFile(MutableDomItem(qmlFile));
- });
-
return *m_semanticAnalysis;
}
@@ -1875,7 +1850,9 @@ DomEnvironment::SemanticAnalysis::SemanticAnalysis(const QStringList &loadPaths)
void DomEnvironment::SemanticAnalysis::setLoadPaths(const QStringList &loadPaths)
{
- // TODO: maybe also update the build paths in m_mapper?
+ if (loadPaths == m_importer->importPaths())
+ return;
+
m_importer->setImportPaths(loadPaths);
}
@@ -1901,12 +1878,18 @@ DomEnvironment::DomEnvironment(const shared_ptr<DomEnvironment> &parent,
void DomEnvironment::addQmlFile(const std::shared_ptr<QmlFile> &file, AddOption options)
{
+ addExternalItem(file, file->canonicalFilePath(), options);
if (domCreationOptions().testFlag(DomCreationOption::WithSemanticAnalysis)) {
const QQmlJSScope::Ptr &handle =
semanticAnalysis().m_importer->importFile(file->canonicalFilePath());
+
+ // force reset the outdated qqmljsscope in case it was already populated
+ QDeferredFactory<QQmlJSScope> newFactory(semanticAnalysis().m_importer.get(),
+ file->canonicalFilePath(),
+ TypeReader{ weak_from_this() });
file->setHandleForPopulation(handle);
+ handle.resetFactory(std::move(newFactory));
}
- addExternalItem(file, file->canonicalFilePath(), options);
}
void DomEnvironment::addQmlDirectory(const std::shared_ptr<QmlDirectory> &file, AddOption options)
@@ -1934,6 +1917,36 @@ void DomEnvironment::addGlobalScope(const std::shared_ptr<GlobalScope> &scope, A
addExternalItem(scope, scope->name(), options);
}
+QList<QQmlJS::DiagnosticMessage>
+DomEnvironment::TypeReader::operator()(QQmlJSImporter *importer, const QString &filePath,
+ const QSharedPointer<QQmlJSScope> &scopeToPopulate)
+{
+ Q_UNUSED(importer);
+ Q_UNUSED(scopeToPopulate);
+
+ const QFileInfo info{ filePath };
+ const QString baseName = info.baseName();
+ scopeToPopulate->setInternalName(baseName.endsWith(QStringLiteral(".ui")) ? baseName.chopped(3)
+ : baseName);
+
+ std::shared_ptr<DomEnvironment> envPtr = m_env.lock();
+ // populate QML File if from implicit import directory
+ // use the version in DomEnvironment and do *not* load from disk.
+ auto it = envPtr->m_qmlFileWithPath.constFind(filePath);
+ if (it == envPtr->m_qmlFileWithPath.constEnd()) {
+ qCDebug(domLog) << "Import visitor tried to lazily load file \"" << filePath
+ << "\", but that file was not found in the DomEnvironment. Was this "
+ "file not discovered by the Dom's dependency loading mechanism?";
+ return { QQmlJS::DiagnosticMessage{
+ u"Could not find file \"%1\" in the Dom."_s.arg(filePath), QtMsgType::QtWarningMsg,
+ SourceLocation{} } };
+ }
+ const DomItem qmlFile = it.value()->currentItem(DomItem(envPtr));
+ envPtr->populateFromQmlFile(MutableDomItem(qmlFile));
+ return {};
+}
+
+
bool DomEnvironment::commitToBase(
const DomItem &self, const shared_ptr<DomEnvironment> &validEnvPtr)
{
@@ -1947,6 +1960,7 @@ bool DomEnvironment::commitToBase(
QMap<QString, std::shared_ptr<ExternalItemInfo<JsFile>>> my_jsFileWithPath;
QMap<QString, std::shared_ptr<ExternalItemInfo<QmltypesFile>>> my_qmltypesFileWithPath;
QHash<Path, std::shared_ptr<LoadInfo>> my_loadInfos;
+ std::optional<SemanticAnalysis> my_semanticAnalysis;
{
QMutexLocker l(mutex());
my_moduleIndexWithUri = m_moduleIndexWithUri;
@@ -1957,10 +1971,11 @@ bool DomEnvironment::commitToBase(
my_jsFileWithPath = m_jsFileWithPath;
my_qmltypesFileWithPath = m_qmltypesFileWithPath;
my_loadInfos = m_loadInfos;
+ my_semanticAnalysis = semanticAnalysis();
}
{
QMutexLocker lBase(base()->mutex()); // be more careful about makeCopy calls with lock?
- m_base->m_semanticAnalysis = m_semanticAnalysis;
+ m_base->m_semanticAnalysis = my_semanticAnalysis;
m_base->m_globalScopeWithName.insert(my_globalScopeWithName);
m_base->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
m_base->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
@@ -1993,7 +2008,7 @@ bool DomEnvironment::commitToBase(
if (m_lastValidBase) {
QMutexLocker lValid(
m_lastValidBase->mutex()); // be more careful about makeCopy calls with lock?
- m_base->m_semanticAnalysis = m_semanticAnalysis;
+ m_lastValidBase->m_semanticAnalysis = std::move(my_semanticAnalysis);
m_lastValidBase->m_globalScopeWithName.insert(my_globalScopeWithName);
m_lastValidBase->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
m_lastValidBase->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
@@ -2022,6 +2037,25 @@ bool DomEnvironment::commitToBase(
}
}
}
+
+ auto newBaseForPopulation =
+ m_lastValidBase ? m_lastValidBase->weak_from_this() : m_base->weak_from_this();
+ // adapt the factory to the use the base or valid environment for unpopulated files, instead of
+ // the current environment which will very probably be destroyed anytime soon
+ for (const auto &qmlFile : my_qmlFileWithPath) {
+ if (!qmlFile || !qmlFile->current)
+ continue;
+ QQmlJSScope::ConstPtr handle = qmlFile->current->handleForPopulation();
+ if (!handle)
+ continue;
+ auto oldFactory = handle.factory();
+ if (!oldFactory)
+ continue;
+
+ const QDeferredFactory<QQmlJSScope> newFactory(
+ oldFactory->importer(), oldFactory->filePath(), TypeReader{ newBaseForPopulation });
+ handle.resetFactory(newFactory);
+ }
return true;
}
@@ -2174,9 +2208,10 @@ void DomEnvironment::clearReferenceCache()
void DomEnvironment::populateFromQmlFile(MutableDomItem &&qmlFile)
{
if (std::shared_ptr<QmlFile> qmlFilePtr = qmlFile.ownerAs<QmlFile>()) {
- QQmlJSLogger logger; // TODO
- // the logger filename is used to populate the QQmlJSScope filepath.
+ QQmlJSLogger logger;
logger.setFileName(qmlFile.canonicalFilePath());
+ logger.setCode(qmlFilePtr->code());
+ logger.setSilent(true);
auto setupFile = [&qmlFilePtr, &qmlFile, this](auto &&visitor) {
Q_UNUSED(this); // note: integrity requires "this" to be in the capture list, while
diff --git a/src/qmldom/qqmldomtop_p.h b/src/qmldom/qqmldomtop_p.h
index 33a921af93..afdea6b311 100644
--- a/src/qmldom/qqmldomtop_p.h
+++ b/src/qmldom/qqmldomtop_p.h
@@ -721,6 +721,15 @@ class QMLDOM_EXPORT DomEnvironment final : public DomTop,
protected:
std::shared_ptr<OwningItem> doCopy(const DomItem &self) const override;
+private:
+ struct TypeReader
+ {
+ std::weak_ptr<DomEnvironment> m_env;
+
+ QList<QQmlJS::DiagnosticMessage>
+ operator()(QQmlJSImporter *importer, const QString &filePath,
+ const QSharedPointer<QQmlJSScope> &scopeToPopulate);
+ };
public:
enum class Option {
Default = 0x0,
diff --git a/src/qmlintegration/qqmlintegration.h b/src/qmlintegration/qqmlintegration.h
index 1e40ceec17..0cea1bab30 100644
--- a/src/qmlintegration/qqmlintegration.h
+++ b/src/qmlintegration/qqmlintegration.h
@@ -45,12 +45,16 @@ QT_END_NAMESPACE
#define QML_ELEMENT \
Q_CLASSINFO("QML.Element", "auto")
+
#define QML_ANONYMOUS \
Q_CLASSINFO("QML.Element", "anonymous") \
enum class QmlIsAnonymous{yes = true}; \
template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlAnonymous; \
+ QT_WARNING_PUSH \
+ QT_WARNING_DISABLE_GCC("-Wredundant-decls") \
template<typename... Args> \
friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *); \
+ QT_WARNING_POP \
inline constexpr void qt_qmlMarker_anonymous() {}
#define QML_NAMED_ELEMENT(NAME) \
@@ -61,8 +65,11 @@ QT_END_NAMESPACE
Q_CLASSINFO("QML.UncreatableReason", REASON) \
enum class QmlIsUncreatable {yes = true}; \
template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlUncreatable; \
+ QT_WARNING_PUSH \
+ QT_WARNING_DISABLE_GCC("-Wredundant-decls") \
template<typename... Args> \
friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *); \
+ QT_WARNING_POP \
inline constexpr void qt_qmlMarker_uncreatable() {}
#define QML_VALUE_TYPE(NAME) \
@@ -80,8 +87,11 @@ QT_END_NAMESPACE
Q_CLASSINFO("QML.Singleton", "true") \
enum class QmlIsSingleton {yes = true}; \
template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlSingleton; \
+ QT_WARNING_PUSH \
+ QT_WARNING_DISABLE_GCC("-Wredundant-decls") \
template<typename... Args> \
friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *); \
+ QT_WARNING_POP \
inline constexpr void qt_qmlMarker_singleton() {}
#define QML_ADDED_IN_MINOR_VERSION(VERSION) \
@@ -110,8 +120,11 @@ QT_END_NAMESPACE
Q_CLASSINFO("QML.Extended", #EXTENDED_TYPE) \
using QmlExtendedType = EXTENDED_TYPE; \
template<class, class> friend struct QML_PRIVATE_NAMESPACE::QmlExtended; \
+ QT_WARNING_PUSH \
+ QT_WARNING_DISABLE_GCC("-Wredundant-decls") \
template<typename... Args> \
friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *); \
+ QT_WARNING_POP \
inline constexpr void qt_qmlMarker_extended() {}
#define QML_EXTENDED_NAMESPACE(EXTENDED_NAMESPACE) \
@@ -119,8 +132,11 @@ QT_END_NAMESPACE
Q_CLASSINFO("QML.ExtensionIsNamespace", "true") \
static constexpr const QMetaObject *qmlExtendedNamespace() { return &EXTENDED_NAMESPACE::staticMetaObject; } \
template<class, class> friend struct QML_PRIVATE_NAMESPACE::QmlExtendedNamespace; \
+ QT_WARNING_PUSH \
+ QT_WARNING_DISABLE_GCC("-Wredundant-decls") \
template<typename... Args> \
friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *); \
+ QT_WARNING_POP \
inline constexpr void qt_qmlMarker_extendedNamespace() {}
#define QML_NAMESPACE_EXTENDED(EXTENDED_NAMESPACE) \
@@ -130,8 +146,11 @@ QT_END_NAMESPACE
Q_CLASSINFO("QML.Element", "anonymous") \
enum class QmlIsInterface {yes = true}; \
template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlInterface; \
+ QT_WARNING_PUSH \
+ QT_WARNING_DISABLE_GCC("-Wredundant-decls") \
template<typename... Args> \
friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *); \
+ QT_WARNING_POP \
inline constexpr void qt_qmlMarker_interface() {}
#define QML_IMPLEMENTS_INTERFACES(INTERFACES) \
@@ -144,8 +163,11 @@ QT_END_NAMESPACE
using QmlSequenceValueType = VALUE_TYPE; \
enum class QmlIsSequence {yes = true}; \
template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlSequence; \
+ QT_WARNING_PUSH \
+ QT_WARNING_DISABLE_GCC("-Wredundant-decls") \
template<typename... Args> \
friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *); \
+ QT_WARNING_POP \
inline constexpr void qt_qmlMarker_sequence() {}
#define QML_UNAVAILABLE \
@@ -155,8 +177,11 @@ QT_END_NAMESPACE
Q_CLASSINFO("QML.Foreign", #FOREIGN_TYPE) \
using QmlForeignType = FOREIGN_TYPE; \
template<class, class> friend struct QML_PRIVATE_NAMESPACE::QmlResolved; \
+ QT_WARNING_PUSH \
+ QT_WARNING_DISABLE_GCC("-Wredundant-decls") \
template<typename... Args> \
friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *); \
+ QT_WARNING_POP \
inline constexpr void qt_qmlMarker_foreign() {}
#define QML_FOREIGN_NAMESPACE(FOREIGN_NAMESPACE) \
@@ -167,4 +192,8 @@ QT_END_NAMESPACE
#define QML_CUSTOMPARSER \
Q_CLASSINFO("QML.HasCustomParser", "true")
+#define QML_USING(ORIGINAL) \
+ using QmlUsing ## ORIGINAL = ORIGINAL; \
+ Q_CLASSINFO("QML.Using", #ORIGINAL)
+
#endif
diff --git a/src/qmlls/CMakeLists.txt b/src/qmlls/CMakeLists.txt
index d00e2775c8..2061f5cebe 100644
--- a/src/qmlls/CMakeLists.txt
+++ b/src/qmlls/CMakeLists.txt
@@ -31,6 +31,10 @@ qt_internal_add_module(QmlLSPrivate
qqmllscompletion.cpp qqmllscompletion_p.h
qqmllscompletionplugin.cpp qqmllscompletionplugin_p.h
qdochtmlparser_p.h qdochtmlparser.cpp
+ qqmlhighlightsupport_p.h qqmlhighlightsupport.cpp
+ qqmlsemantictokens_p.h qqmlsemantictokens.cpp
+ qqmllshelpplugininterface_p.h qqmllshelpplugininterface.cpp
+ qqmllshelputils_p.h qqmllshelputils.cpp
PUBLIC_LIBRARIES
Qt::LanguageServerPrivate
diff --git a/src/qmlls/qdochtmlparser.cpp b/src/qmlls/qdochtmlparser.cpp
index bba18facb5..bf885fb258 100644
--- a/src/qmlls/qdochtmlparser.cpp
+++ b/src/qmlls/qdochtmlparser.cpp
@@ -8,8 +8,6 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-namespace { //anonymous
-
// An emprical value to avoid too much content
static constexpr qsizetype firstIndexOfParagraphTag = 400;
@@ -20,7 +18,7 @@ static constexpr auto lengthOfStartParagraphTag = qsizetype(std::char_traits<cha
static constexpr auto lengthOfEndParagraphTag = qsizetype(std::char_traits<char>::length("</p>"));
static constexpr auto lengthOfPeriod = qsizetype(std::char_traits<char>::length("."));
-QString getContentsByMarks(const QString &html, QString startMark, QString endMark)
+static QString getContentsByMarks(const QString &html, QString startMark, QString endMark)
{
startMark.prepend("$$$"_L1);
endMark.prepend("<!-- @@@"_L1);
@@ -41,7 +39,7 @@ QString getContentsByMarks(const QString &html, QString startMark, QString endMa
}
-void stripAllHtml(QString *html)
+static void stripAllHtml(QString *html)
{
Q_ASSERT(html);
html->remove(QRegularExpression("<.*?>"_L1));
@@ -51,7 +49,7 @@ void stripAllHtml(QString *html)
\brief Process the string obtained from start mark to end mark.
This is duplicated from QtC's Utils::HtmlExtractor, modified on top of it.
*/
-void processOutput(QString *html)
+static void processOutput(QString *html)
{
Q_ASSERT(html);
if (html->isEmpty())
@@ -95,43 +93,30 @@ void processOutput(QString *html)
}
}
-}
-
-QDocHtmlExtractor::QDocHtmlExtractor(const QString &code) : m_code{ code }
+class ExtractQmlType : public HtmlExtractor
{
-}
+public:
+ QString extract(const QString &code, const QString &keyword, ExtractionMode mode) override;
+};
-QString QDocHtmlExtractor::extract(const QDocHtmlExtractor::Element &element, ExtractionMode mode)
+class ExtractQmlProperty : public HtmlExtractor
{
- QString result;
- switch (element.type) {
- case ElementType::QmlType:
- result = parseForQmlType(element.name, mode);
- break;
+public:
+ QString extract(const QString &code, const QString &keyword, ExtractionMode mode) override;
+};
- case ElementType::QmlProperty:
- result = parseForQmlProperty(element.name, mode);
- break;
- case ElementType::QmlMethod:
- case ElementType::QmlSignal:
- result = parseForQmlMethodOrSignal(element.name, mode);
- break;
- default:
- return {};
- }
-
- stripAllHtml(&result);
-
- // Also remove leading and trailing whitespaces
- return result.trimmed();
-}
+class ExtractQmlMethodOrSignal : public HtmlExtractor
+{
+public:
+ QString extract(const QString &code, const QString &keyword, ExtractionMode mode) override;
+};
-QString QDocHtmlExtractor::parseForQmlType(const QString &element, ExtractionMode mode)
+QString ExtractQmlType::extract(const QString &code, const QString &element, ExtractionMode mode)
{
QString result;
// Get brief description
- if (mode == QDocHtmlExtractor::ExtractionMode::Simplified) {
- result = getContentsByMarks(m_code, element + "-brief"_L1 , element);
+ if (mode == ExtractionMode::Simplified) {
+ result = getContentsByMarks(code, element + "-brief"_L1 , element);
// Remove More...
if (!result.isEmpty()) {
const auto tailToRemove = "More..."_L1;
@@ -140,7 +125,7 @@ QString QDocHtmlExtractor::parseForQmlType(const QString &element, ExtractionMod
result.remove(lastIndex, tailToRemove.length());
}
} else {
- result = getContentsByMarks(m_code, element + "-description"_L1, element);
+ result = getContentsByMarks(code, element + "-description"_L1, element);
// Remove header
if (!result.isEmpty()) {
const auto headerToRemove = "Detailed Description"_L1;
@@ -150,25 +135,26 @@ QString QDocHtmlExtractor::parseForQmlType(const QString &element, ExtractionMod
}
}
- return result;
+ stripAllHtml(&result);
+ return result.trimmed();
}
-QString QDocHtmlExtractor::parseForQmlProperty(const QString &element, ExtractionMode mode)
+QString ExtractQmlProperty::extract(const QString &code, const QString &keyword, ExtractionMode mode)
{
// Qt 5.15 way of finding properties in doc
- QString startMark = QString::fromLatin1("<a name=\"%1-prop\">").arg(element);
- qsizetype startIndex = m_code.indexOf(startMark);
+ QString startMark = QString::fromLatin1("<a name=\"%1-prop\">").arg(keyword);
+ qsizetype startIndex = code.indexOf(startMark);
if (startIndex == -1) {
// if not found, try Qt6
startMark = QString::fromLatin1(
"<td class=\"tblQmlPropNode\"><p>\n<span class=\"name\">%1</span>")
- .arg(element);
- startIndex = m_code.indexOf(startMark);
+ .arg(keyword);
+ startIndex = code.indexOf(startMark);
if (startIndex == -1)
return {};
}
- QString contents = m_code.mid(startIndex + startMark.size());
+ QString contents = code.mid(startIndex + startMark.size());
startIndex = contents.indexOf(QLatin1String("<div class=\"qmldoc\"><p>"));
if (startIndex == -1)
return {};
@@ -176,39 +162,66 @@ QString QDocHtmlExtractor::parseForQmlProperty(const QString &element, Extractio
contents = contents.mid(startIndex);
if (mode == ExtractionMode::Simplified)
processOutput(&contents);
- return contents;
+ stripAllHtml(&contents);
+ return contents.trimmed();
}
-QString QDocHtmlExtractor::parseForQmlMethodOrSignal(const QString &functionName, ExtractionMode mode)
+QString ExtractQmlMethodOrSignal::extract(const QString &code, const QString &keyword, ExtractionMode mode)
{
// the case with <!-- $$$childAt[overload1]$$$childAtrealreal -->
- QString mark = QString::fromLatin1("$$$%1[overload1]$$$%1").arg(functionName);
- qsizetype startIndex = m_code.indexOf(mark);
+ QString mark = QString::fromLatin1("$$$%1[overload1]$$$%1").arg(keyword);
+ qsizetype startIndex = code.indexOf(mark);
if (startIndex != -1) {
- startIndex = m_code.indexOf("-->"_L1, startIndex + mark.length());
+ startIndex = code.indexOf("-->"_L1, startIndex + mark.length());
if (startIndex == -1)
return {};
} else {
// it could be part of the method list
mark = QString::fromLatin1("<span class=\"name\">%1</span>")
- .arg(functionName);
- startIndex = m_code.indexOf(mark);
+ .arg(keyword);
+ startIndex = code.indexOf(mark);
if (startIndex != -1)
startIndex += mark.length();
else
return {};
}
- startIndex = m_code.indexOf(QLatin1String("<div class=\"qmldoc\"><p>"), startIndex);
+ startIndex = code.indexOf(QLatin1String("<div class=\"qmldoc\"><p>"), startIndex);
if (startIndex == -1)
return {};
QString endMark = QString::fromLatin1("<!-- @@@");
- qsizetype endIndex = m_code.indexOf(endMark, startIndex);
- QString contents = m_code.mid(startIndex, endIndex);
+ qsizetype endIndex = code.indexOf(endMark, startIndex);
+ QString contents = code.mid(startIndex, endIndex);
if (mode == ExtractionMode::Simplified)
processOutput(&contents);
- return contents;
+ stripAllHtml(&contents);
+ return contents.trimmed();
+}
+
+ExtractDocumentation::ExtractDocumentation(QQmlJS::Dom::DomType domType)
+{
+ using namespace QQmlJS::Dom;
+ switch (domType) {
+ case DomType::QmlObject:
+ m_extractor = std::make_unique<ExtractQmlType>();
+ break;
+ case DomType::Binding:
+ case DomType::PropertyDefinition:
+ m_extractor = std::make_unique<ExtractQmlProperty>();
+ break;
+ case DomType::MethodInfo:
+ m_extractor = std::make_unique<ExtractQmlMethodOrSignal>();
+ break;
+ default:
+ break;
+ }
+}
+
+QString ExtractDocumentation::execute(const QString &code, const QString &keyword, HtmlExtractor::ExtractionMode mode)
+{
+ Q_ASSERT(m_extractor);
+ return m_extractor->extract(code, keyword, mode);
}
QT_END_NAMESPACE
diff --git a/src/qmlls/qdochtmlparser_p.h b/src/qmlls/qdochtmlparser_p.h
index f66fb0e56b..d09f2f882e 100644
--- a/src/qmlls/qdochtmlparser_p.h
+++ b/src/qmlls/qdochtmlparser_p.h
@@ -15,35 +15,27 @@
// We mean it.
//
+#include <QtQmlDom/private/qqmldomtop_p.h>
#include <QString>
QT_BEGIN_NAMESPACE
-class QDocHtmlExtractor
+class HtmlExtractor
{
public:
enum class ExtractionMode : char { Simplified, Extended };
- enum class ElementType : char {
- QmlType,
- QmlProperty,
- QmlMethod,
- QmlSignal
- };
- struct Element {
- QString name;
- ElementType type;
- };
-
- QDocHtmlExtractor(const QString &code);
- QString extract(const Element &element, ExtractionMode extractionMode);
+ virtual QString extract(const QString &code, const QString &keyword, ExtractionMode mode) = 0;
+ virtual ~HtmlExtractor() = default;
+};
+class ExtractDocumentation
+{
+public:
+ ExtractDocumentation(QQmlJS::Dom::DomType domType);
+ QString execute(const QString &code, const QString &keyword, HtmlExtractor::ExtractionMode mode);
private:
- QString parseForQmlType(const QString &element, ExtractionMode mode);
- QString parseForQmlProperty(const QString &element, ExtractionMode mode = ExtractionMode::Simplified);
- QString parseForQmlMethodOrSignal(const QString &functionName, ExtractionMode mode);
-
- const QString &m_code;
+ std::unique_ptr<HtmlExtractor> m_extractor;
};
QT_END_NAMESPACE
diff --git a/src/qmlls/qlanguageserver.cpp b/src/qmlls/qlanguageserver.cpp
index b65873ef5d..6b6c4699cc 100644
--- a/src/qmlls/qlanguageserver.cpp
+++ b/src/qmlls/qlanguageserver.cpp
@@ -226,9 +226,15 @@ const QLspSpecification::InitializeResult &QLanguageServer::serverInfo() const
return d->serverInfo;
}
-void QLanguageServer::receiveData(const QByteArray &d)
+void QLanguageServer::receiveData(const QByteArray &data, bool isEndOfMessage)
{
- protocol()->receiveData(d);
+ if (!data.isEmpty())
+ protocol()->receiveData(data);
+
+ const Q_D(QLanguageServer);
+ // read next message if not shutting down
+ if (isEndOfMessage && d->runStatus != RunStatus::Stopped)
+ emit readNextMessage();
}
void QLanguageServer::registerHandlers(QLanguageServerProtocol *protocol)
diff --git a/src/qmlls/qlanguageserver_p.h b/src/qmlls/qlanguageserver_p.h
index 019a059823..53118c00c8 100644
--- a/src/qmlls/qlanguageserver_p.h
+++ b/src/qmlls/qlanguageserver_p.h
@@ -73,13 +73,14 @@ public:
const QLspSpecification::InitializeResult &serverInfo() const;
public Q_SLOTS:
- void receiveData(const QByteArray &d);
+ void receiveData(const QByteArray &d, bool isEndOfMessage);
Q_SIGNALS:
void runStatusChanged(RunStatus);
void clientInitialized(QLanguageServer *server);
void shutdown();
void exit();
void lifecycleError();
+ void readNextMessage();
private:
void registerMethods(QJsonRpc::TypedRpc &typedRpc);
diff --git a/src/qmlls/qqmlbasemodule_p.h b/src/qmlls/qqmlbasemodule_p.h
index 47596914cb..294b38fa40 100644
--- a/src/qmlls/qqmlbasemodule_p.h
+++ b/src/qmlls/qqmlbasemodule_p.h
@@ -55,7 +55,7 @@ struct ResponseScopeGuard
{
Q_DISABLE_COPY_MOVE(ResponseScopeGuard)
- std::variant<Result *, QQmlLSUtilsErrorMessage> m_response;
+ std::variant<Result *, QQmlLSUtils::ErrorMessage> m_response;
ResponseCallback &m_callback;
ResponseScopeGuard(Result &results, ResponseCallback &callback)
@@ -64,15 +64,15 @@ struct ResponseScopeGuard
}
// note: discards the current result or error message, if there is any
- void setError(const QQmlLSUtilsErrorMessage &error) { m_response = error; }
+ void setError(const QQmlLSUtils::ErrorMessage &error) { m_response = error; }
template<typename... T>
bool setErrorFrom(const std::variant<T...> &variant)
{
- static_assert(std::disjunction_v<std::is_same<T, QQmlLSUtilsErrorMessage>...>,
+ static_assert(std::disjunction_v<std::is_same<T, QQmlLSUtils::ErrorMessage>...>,
"ResponseScopeGuard::setErrorFrom was passed a variant that never contains"
" an error message.");
- if (auto x = std::get_if<QQmlLSUtilsErrorMessage>(&variant)) {
+ if (auto x = std::get_if<QQmlLSUtils::ErrorMessage>(&variant)) {
setError(*x);
return true;
}
@@ -89,7 +89,7 @@ struct ResponseScopeGuard
// xxx was not an error, continue
\endcode
*/
- bool setErrorFrom(const std::optional<QQmlLSUtilsErrorMessage> &error)
+ bool setErrorFrom(const std::optional<QQmlLSUtils::ErrorMessage> &error)
{
if (error) {
setError(*error);
@@ -101,7 +101,7 @@ struct ResponseScopeGuard
~ResponseScopeGuard()
{
std::visit(qOverloadedVisitor{ [this](Result *result) { m_callback.sendResponse(*result); },
- [this](const QQmlLSUtilsErrorMessage &error) {
+ [this](const QQmlLSUtils::ErrorMessage &error) {
m_callback.sendErrorResponse(error.code,
error.message.toUtf8());
} },
@@ -125,7 +125,7 @@ struct QQmlBaseModule : public QLanguageServerModule
decltype(auto) getRequestHandler();
// processes a request in a different thread.
virtual void process(RequestPointerArgument toBeProcessed) = 0;
- std::variant<QList<QQmlLSUtilsItemLocation>, QQmlLSUtilsErrorMessage>
+ std::variant<QList<QQmlLSUtils::ItemLocation>, QQmlLSUtils::ErrorMessage>
itemsForRequest(const RequestPointer &request);
public Q_SLOTS:
@@ -228,7 +228,7 @@ void QQmlBaseModule<RequestType>::updatedSnapshot(const QByteArray &url)
}
template<typename RequestType>
-std::variant<QList<QQmlLSUtilsItemLocation>, QQmlLSUtilsErrorMessage>
+std::variant<QList<QQmlLSUtils::ItemLocation>, QQmlLSUtils::ErrorMessage>
QQmlBaseModule<RequestType>::itemsForRequest(const RequestPointer &request)
{
@@ -236,9 +236,9 @@ QQmlBaseModule<RequestType>::itemsForRequest(const RequestPointer &request)
QQmlLSUtils::lspUriToQmlUrl(request->m_parameters.textDocument.uri));
if (!doc.snapshot.validDocVersion || doc.snapshot.validDocVersion != doc.snapshot.docVersion) {
- return QQmlLSUtilsErrorMessage{ 0,
- u"Cannot proceed: current QML document is invalid! Fix"
- u" all the errors in your QML code and try again."_s };
+ return QQmlLSUtils::ErrorMessage{ 0,
+ u"Cannot proceed: current QML document is invalid! Fix"
+ u" all the errors in your QML code and try again."_s };
}
QQmlJS::Dom::DomItem file = doc.snapshot.validDoc.fileObject(QQmlJS::Dom::GoTo::MostLikely);
@@ -246,7 +246,7 @@ QQmlBaseModule<RequestType>::itemsForRequest(const RequestPointer &request)
if (auto envPtr = file.environment().ownerAs<QQmlJS::Dom::DomEnvironment>())
envPtr->clearReferenceCache();
if (!file) {
- return QQmlLSUtilsErrorMessage{
+ return QQmlLSUtils::ErrorMessage{
0,
u"Could not find file %1 in project."_s.arg(doc.snapshot.doc.toString()),
};
@@ -256,7 +256,7 @@ QQmlBaseModule<RequestType>::itemsForRequest(const RequestPointer &request)
request->m_parameters.position.character);
if (itemsFound.isEmpty()) {
- return QQmlLSUtilsErrorMessage{
+ return QQmlLSUtils::ErrorMessage{
0,
u"Could not find any items at given text location."_s,
};
diff --git a/src/qmlls/qqmlcodemodel.cpp b/src/qmlls/qqmlcodemodel.cpp
index 726fdc1cfb..e3a6315e6f 100644
--- a/src/qmlls/qqmlcodemodel.cpp
+++ b/src/qmlls/qqmlcodemodel.cpp
@@ -320,6 +320,18 @@ OpenDocument QQmlCodeModel::openDocumentByUrl(const QByteArray &url)
return m_openDocuments.value(url);
}
+RegisteredSemanticTokens &QQmlCodeModel::registeredTokens()
+{
+ QMutexLocker l(&m_mutex);
+ return m_tokens;
+}
+
+const RegisteredSemanticTokens &QQmlCodeModel::registeredTokens() const
+{
+ QMutexLocker l(&m_mutex);
+ return m_tokens;
+}
+
void QQmlCodeModel::indexNeedsUpdate()
{
const int maxIndexThreads = 1;
@@ -597,6 +609,18 @@ void QQmlCodeModel::newDocForOpenFile(const QByteArray &url, int version, const
if (std::shared_ptr<DomEnvironment> newCurrentPtr = newCurrent.ownerAs<DomEnvironment>()) {
newCurrentPtr->setLoadPaths(loadPaths);
}
+
+ // if the documentation root path is not set through the commandline,
+ // try to set it from the settings file (.qmlls.ini file)
+ if (m_documentationRootPath.isEmpty()) {
+ QString path = url2Path(url);
+ if (m_settings && m_settings->search(path)) {
+ QString docDir = QStringLiteral(u"docDir");
+ if (m_settings->isSet(docDir))
+ setDocumentationRootPath(m_settings->value(docDir).toString());
+ }
+ }
+
Path p;
auto newCurrentPtr = newCurrent.ownerAs<DomEnvironment>();
newCurrentPtr->loadFile(FileToLoad::fromMemory(newCurrentPtr, fPath, docText),
@@ -796,6 +820,15 @@ QStringList QQmlCodeModel::buildPathsForFileUrl(const QByteArray &url)
return res;
}
+void QQmlCodeModel::setDocumentationRootPath(const QString &path)
+{
+ QMutexLocker l(&m_mutex);
+ if (m_documentationRootPath != path) {
+ m_documentationRootPath = path;
+ emit documentationRootPathChanged(path);
+ }
+}
+
void QQmlCodeModel::setBuildPathsForRootUrl(QByteArray url, const QStringList &paths)
{
QMutexLocker l(&m_mutex);
diff --git a/src/qmlls/qqmlcodemodel_p.h b/src/qmlls/qqmlcodemodel_p.h
index 8e2be96ef6..38aec2c244 100644
--- a/src/qmlls/qqmlcodemodel_p.h
+++ b/src/qmlls/qqmlcodemodel_p.h
@@ -71,6 +71,12 @@ struct ToIndex
int leftDepth;
};
+struct RegisteredSemanticTokens
+{
+ QByteArray resultId = "0";
+ QList<int> lastTokens;
+};
+
class QQmlCodeModel : public QObject
{
Q_OBJECT
@@ -80,8 +86,8 @@ public:
explicit QQmlCodeModel(QObject *parent = nullptr, QQmlToolingSettings *settings = nullptr);
~QQmlCodeModel();
- QQmlJS::Dom::DomItem currentEnv();
- QQmlJS::Dom::DomItem validEnv();
+ QQmlJS::Dom::DomItem currentEnv() const { return m_currentEnv; };
+ QQmlJS::Dom::DomItem validEnv() const { return m_validEnv; };
OpenDocumentSnapshot snapshotByUrl(const QByteArray &url);
OpenDocument openDocumentByUrl(const QByteArray &url);
@@ -104,13 +110,21 @@ public:
QStringList importPaths() const { return m_importPaths; };
void setImportPaths(const QStringList &paths) { m_importPaths = paths; };
void removeRootUrls(const QList<QByteArray> &urls);
- QQmlToolingSettings *settings();
+ QQmlToolingSettings *settings() const { return m_settings; }
QStringList findFilePathsFromFileNames(const QStringList &fileNames) const;
static QStringList fileNamesToWatch(const QQmlJS::Dom::DomItem &qmlFile);
void disableCMakeCalls();
const QFactoryLoader &pluginLoader() const { return m_pluginLoader; }
+
+ RegisteredSemanticTokens &registeredTokens();
+ const RegisteredSemanticTokens &registeredTokens() const;
+ QString documentationRootPath() const { return m_documentationRootPath; }
+ void setDocumentationRootPath(const QString &path);
+
Q_SIGNALS:
void updatedSnapshot(const QByteArray &url);
+ void documentationRootPathChanged(const QString &path);
+
private:
void indexDirectory(const QString &path, int depthLeft);
int indexEvalProgress() const; // to be called in the mutex
@@ -153,6 +167,8 @@ private:
QFactoryLoader m_pluginLoader;
bool m_rebuildRequired = true; // always trigger a rebuild on start
CMakeStatus m_cmakeStatus = RequiresInitialization;
+ RegisteredSemanticTokens m_tokens;
+ QString m_documentationRootPath;
private slots:
void onCppFileChanged(const QString &);
};
diff --git a/src/qmlls/qqmlcompletionsupport.cpp b/src/qmlls/qqmlcompletionsupport.cpp
index 371a5eb447..632a5e902a 100644
--- a/src/qmlls/qqmlcompletionsupport.cpp
+++ b/src/qmlls/qqmlcompletionsupport.cpp
@@ -169,6 +169,11 @@ QList<CompletionItem> CompletionRequest::completions(QmlLsp::OpenDocumentSnapsho
auto itemsFound = QQmlLSUtils::itemsFromTextLocation(file, m_parameters.position.line,
m_parameters.position.character
- ctx.filterChars().size());
+ if (itemsFound.isEmpty()) {
+ qCDebug(QQmlLSCompletionLog) << "No items found for completions at" << urlAndPos();
+ return {};
+ }
+
if (itemsFound.size() > 1) {
QStringList paths;
for (auto &it : itemsFound)
@@ -176,11 +181,7 @@ QList<CompletionItem> CompletionRequest::completions(QmlLsp::OpenDocumentSnapsho
qCWarning(QQmlLSCompletionLog) << "Multiple elements of " << urlAndPos()
<< " at the same depth:" << paths << "(using first)";
}
- DomItem currentItem;
- if (!itemsFound.isEmpty())
- currentItem = itemsFound.first().domItem;
- else
- qCDebug(QQmlLSCompletionLog) << "No items found for completions at" << urlAndPos();
+ const DomItem currentItem = itemsFound.first().domItem;
qCDebug(QQmlLSCompletionLog) << "Completion at " << urlAndPos() << " "
<< m_parameters.position.line << ":"
<< m_parameters.position.character << "offset:" << pos
diff --git a/src/qmlls/qqmlcompletionsupport_p.h b/src/qmlls/qqmlcompletionsupport_p.h
index fa0c1ca51a..3d7fa03d94 100644
--- a/src/qmlls/qqmlcompletionsupport_p.h
+++ b/src/qmlls/qqmlcompletionsupport_p.h
@@ -39,7 +39,8 @@ struct CompletionRequest
QString urlAndPos() const;
QList<QLspSpecification::CompletionItem>
completions(QmlLsp::OpenDocumentSnapshot &doc, const QQmlLSCompletion &completionEngine) const;
- DomItem patchInvalidFileForParser(const DomItem& file, qsizetype position) const;
+ QQmlJS::Dom::DomItem patchInvalidFileForParser(const QQmlJS::Dom::DomItem &file,
+ qsizetype position) const;
};
class QmlCompletionSupport : public QQmlBaseModule<CompletionRequest>
diff --git a/src/qmlls/qqmlfindusagessupport.cpp b/src/qmlls/qqmlfindusagessupport.cpp
index 8a3dca7e3a..dc407f71bc 100644
--- a/src/qmlls/qqmlfindusagessupport.cpp
+++ b/src/qmlls/qqmlfindusagessupport.cpp
@@ -44,7 +44,8 @@ void QQmlFindUsagesSupport::process(QQmlFindUsagesSupport::RequestPointerArgumen
if (guard.setErrorFrom(itemsFound))
return;
- QQmlLSUtilsItemLocation &front = std::get<QList<QQmlLSUtilsItemLocation>>(itemsFound).front();
+ QQmlLSUtils::ItemLocation &front =
+ std::get<QList<QQmlLSUtils::ItemLocation>>(itemsFound).front();
auto usages = QQmlLSUtils::findUsagesOf(front.domItem);
@@ -52,7 +53,8 @@ void QQmlFindUsagesSupport::process(QQmlFindUsagesSupport::RequestPointerArgumen
QHash<QString, QString> codeCache;
- for (const auto &usage : usages) {
+ // note: ignore usages in filenames here as that is not supported by the protocol.
+ for (const auto &usage : usages.usagesInFile()) {
QLspSpecification::Location location;
location.uri = QUrl::fromLocalFile(usage.filename).toEncoded();
diff --git a/src/qmlls/qqmlformatting.cpp b/src/qmlls/qqmlformatting.cpp
index 82313f1c65..cf0cdf5147 100644
--- a/src/qmlls/qqmlformatting.cpp
+++ b/src/qmlls/qqmlformatting.cpp
@@ -47,12 +47,12 @@ void QQmlDocumentFormatting::process(RequestPointerArgument request)
DomItem file = doc.snapshot.doc.fileObject(GoTo::MostLikely);
if (!file) {
- guard.setError(QQmlLSUtilsErrorMessage{
+ guard.setError(QQmlLSUtils::ErrorMessage{
0, u"Could not find the file %1"_s.arg(doc.snapshot.doc.canonicalFilePath()) });
return;
}
if (!file.field(Fields::isValid).value().toBool(false)) {
- guard.setError(QQmlLSUtilsErrorMessage{ 0, u"Cannot format invalid documents!"_s });
+ guard.setError(QQmlLSUtils::ErrorMessage{ 0, u"Cannot format invalid documents!"_s });
return;
}
if (auto envPtr = file.environment().ownerAs<DomEnvironment>())
@@ -66,7 +66,7 @@ void QQmlDocumentFormatting::process(RequestPointerArgument request)
return true;
},
true);
- guard.setError(QQmlLSUtilsErrorMessage{
+ guard.setError(QQmlLSUtils::ErrorMessage{
0, u"Failed to parse %1"_s.arg(file.canonicalFilePath()) });
return;
}
diff --git a/src/qmlls/qqmlgotodefinitionsupport.cpp b/src/qmlls/qqmlgotodefinitionsupport.cpp
index 0a5579a057..366fbe7d09 100644
--- a/src/qmlls/qqmlgotodefinitionsupport.cpp
+++ b/src/qmlls/qqmlgotodefinitionsupport.cpp
@@ -47,7 +47,7 @@ void QmlGoToDefinitionSupport::process(RequestPointerArgument request)
if (guard.setErrorFrom(itemsFound))
return;
- QQmlLSUtilsItemLocation &front = std::get<QList<QQmlLSUtilsItemLocation>>(itemsFound).front();
+ auto &front = std::get<QList<QQmlLSUtils::ItemLocation>>(itemsFound).front();
auto location = QQmlLSUtils::findDefinitionOf(front.domItem);
if (!location)
diff --git a/src/qmlls/qqmlgototypedefinitionsupport.cpp b/src/qmlls/qqmlgototypedefinitionsupport.cpp
index d8a0277a62..b29cf3b833 100644
--- a/src/qmlls/qqmlgototypedefinitionsupport.cpp
+++ b/src/qmlls/qqmlgototypedefinitionsupport.cpp
@@ -46,7 +46,7 @@ void QmlGoToTypeDefinitionSupport::process(RequestPointerArgument request)
if (guard.setErrorFrom(itemsFound))
return;
- QQmlLSUtilsItemLocation &front = std::get<QList<QQmlLSUtilsItemLocation>>(itemsFound).front();
+ auto &front = std::get<QList<QQmlLSUtils::ItemLocation>>(itemsFound).front();
auto base = QQmlLSUtils::findTypeDefinitionOf(front.domItem);
diff --git a/src/qmlls/qqmlhighlightsupport.cpp b/src/qmlls/qqmlhighlightsupport.cpp
new file mode 100644
index 0000000000..b3892fbb38
--- /dev/null
+++ b/src/qmlls/qqmlhighlightsupport.cpp
@@ -0,0 +1,212 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <qqmlhighlightsupport_p.h>
+#include <qqmlsemantictokens_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+using namespace QLspSpecification;
+using namespace QQmlJS::Dom;
+
+/*!
+\internal
+Make a list of enum names to register the supported token
+types and modifiers. It is case-sensitive in the protocol
+thus we need to lower the first characters of the enum names.
+*/
+template <typename EnumType>
+static QList<QByteArray> enumToByteArray()
+{
+ QList<QByteArray> result;
+ QMetaEnum metaEnum = QMetaEnum::fromType<EnumType>();
+ for (auto i = 0; i < metaEnum.keyCount(); ++i) {
+ auto &&enumName = QByteArray(metaEnum.key(i));
+ enumName.front() = std::tolower(enumName.front());
+ result.emplace_back(std::move(enumName));
+ }
+
+ return result;
+}
+
+static QList<QByteArray> tokenTypesList()
+{
+ return enumToByteArray<SemanticTokenTypes>();
+}
+
+static QList<QByteArray> tokenModifiersList()
+{
+ return enumToByteArray<SemanticTokenModifiers>();
+}
+
+/*!
+\internal
+A wrapper class that handles the semantic tokens request for a whole file as described in
+https://microsoft.github.io/language-server-protocol/specifications/specification-3-16/#semanticTokens_fullRequest
+Sends a QLspSpecification::SemanticTokens data as response that is generated for the entire file.
+*/
+SemanticTokenFullHandler::SemanticTokenFullHandler(QmlLsp::QQmlCodeModel *codeModel)
+ : QQmlBaseModule(codeModel)
+{
+}
+
+void SemanticTokenFullHandler::process(
+ QQmlBaseModule<SemanticTokensRequest>::RequestPointerArgument request)
+{
+ if (!request) {
+ qCWarning(semanticTokens) << "No semantic token request is available!";
+ return;
+ }
+
+ Responses::SemanticTokensResultType result;
+ ResponseScopeGuard guard(result, request->m_response);
+ const auto doc = m_codeModel->openDocumentByUrl(
+ QQmlLSUtils::lspUriToQmlUrl(request->m_parameters.textDocument.uri));
+ DomItem file = doc.snapshot.doc.fileObject(GoTo::MostLikely);
+ Highlights highlights;
+ auto &&encoded = highlights.collectTokens(file, std::nullopt);
+ auto &registeredTokens = m_codeModel->registeredTokens();
+ if (!encoded.isEmpty()) {
+ HighlightingUtils::updateResultID(registeredTokens.resultId);
+ result = SemanticTokens{ registeredTokens.resultId, encoded };
+ registeredTokens.lastTokens = std::move(encoded);
+ } else {
+ result = nullptr;
+ }
+}
+
+void SemanticTokenFullHandler::registerHandlers(QLanguageServer *, QLanguageServerProtocol *protocol)
+{
+ protocol->registerSemanticTokensRequestHandler(getRequestHandler());
+}
+
+/*!
+\internal
+A wrapper class that handles the semantic tokens delta request for a file
+https://microsoft.github.io/language-server-protocol/specifications/specification-3-16/#semanticTokens_deltaRequest
+Sends either SemanticTokens or SemanticTokensDelta data as response.
+This is generally requested when the text document is edited after receiving full highlighting data.
+*/
+SemanticTokenDeltaHandler::SemanticTokenDeltaHandler(QmlLsp::QQmlCodeModel *codeModel)
+ : QQmlBaseModule(codeModel)
+{
+}
+
+void SemanticTokenDeltaHandler::process(
+ QQmlBaseModule<SemanticTokensDeltaRequest>::RequestPointerArgument request)
+{
+ if (!request) {
+ qCWarning(semanticTokens) << "No semantic token request is available!";
+ return;
+ }
+
+ Responses::SemanticTokensDeltaResultType result;
+ ResponseScopeGuard guard(result, request->m_response);
+ const auto doc = m_codeModel->openDocumentByUrl(
+ QQmlLSUtils::lspUriToQmlUrl(request->m_parameters.textDocument.uri));
+ DomItem file = doc.snapshot.validDoc.fileObject(GoTo::MostLikely);
+ Highlights highlights;
+ auto newEncoded = highlights.collectTokens(file, std::nullopt);
+ auto &registeredTokens = m_codeModel->registeredTokens();
+ const auto lastResultId = registeredTokens.resultId;
+ HighlightingUtils::updateResultID(registeredTokens.resultId);
+
+ // Return full token list if result ids not align
+ // otherwise compute the delta.
+ if (lastResultId == request->m_parameters.previousResultId) {
+ result = QLspSpecification::SemanticTokensDelta {
+ registeredTokens.resultId,
+ HighlightingUtils::computeDiff(registeredTokens.lastTokens, newEncoded)
+ };
+ } else if (!newEncoded.isEmpty()){
+ result = QLspSpecification::SemanticTokens{ registeredTokens.resultId, newEncoded };
+ } else {
+ result = nullptr;
+ }
+ registeredTokens.lastTokens = std::move(newEncoded);
+}
+
+void SemanticTokenDeltaHandler::registerHandlers(QLanguageServer *, QLanguageServerProtocol *protocol)
+{
+ protocol->registerSemanticTokensDeltaRequestHandler(getRequestHandler());
+}
+
+/*!
+\internal
+A wrapper class that handles the semantic tokens range request for a file
+https://microsoft.github.io/language-server-protocol/specifications/specification-3-16/#semanticTokens_rangeRequest
+Sends a QLspSpecification::SemanticTokens data as response that is generated for a range of file.
+*/
+SemanticTokenRangeHandler::SemanticTokenRangeHandler(QmlLsp::QQmlCodeModel *codeModel)
+ : QQmlBaseModule(codeModel)
+{
+}
+
+void SemanticTokenRangeHandler::process(
+ QQmlBaseModule<SemanticTokensRangeRequest>::RequestPointerArgument request)
+{
+ if (!request) {
+ qCWarning(semanticTokens) << "No semantic token request is available!";
+ return;
+ }
+
+ Responses::SemanticTokensRangeResultType result;
+ ResponseScopeGuard guard(result, request->m_response);
+ const auto doc = m_codeModel->openDocumentByUrl(
+ QQmlLSUtils::lspUriToQmlUrl(request->m_parameters.textDocument.uri));
+ DomItem file = doc.snapshot.doc.fileObject(GoTo::MostLikely);
+ const auto qmlFile = file.as<QmlFile>();
+ if (!qmlFile)
+ return;
+ const QString &code = qmlFile->code();
+ const auto range = request->m_parameters.range;
+ int startOffset = int(QQmlLSUtils::textOffsetFrom(code, range.start.line, range.end.character));
+ int endOffset = int(QQmlLSUtils::textOffsetFrom(code, range.end.line, range.end.character));
+ Highlights highlights;
+ auto &&encoded = highlights.collectTokens(file, HighlightsRange{startOffset, endOffset});
+ auto &registeredTokens = m_codeModel->registeredTokens();
+ if (!encoded.isEmpty()) {
+ HighlightingUtils::updateResultID(registeredTokens.resultId);
+ result = SemanticTokens{ registeredTokens.resultId, std::move(encoded) };
+ } else {
+ result = nullptr;
+ }
+}
+
+void SemanticTokenRangeHandler::registerHandlers(QLanguageServer *, QLanguageServerProtocol *protocol)
+{
+ protocol->registerSemanticTokensRangeRequestHandler(getRequestHandler());
+}
+
+QQmlHighlightSupport::QQmlHighlightSupport(QmlLsp::QQmlCodeModel *codeModel)
+ : m_full(codeModel), m_delta(codeModel), m_range(codeModel)
+{
+}
+
+QString QQmlHighlightSupport::name() const
+{
+ return "QQmlHighlightSupport"_L1;
+}
+
+void QQmlHighlightSupport::registerHandlers(QLanguageServer *server, QLanguageServerProtocol *protocol)
+{
+ m_full.registerHandlers(server, protocol);
+ m_delta.registerHandlers(server, protocol);
+ m_range.registerHandlers(server, protocol);
+}
+
+void QQmlHighlightSupport::setupCapabilities(
+ const QLspSpecification::InitializeParams &,
+ QLspSpecification::InitializeResult &serverCapabilities)
+{
+ QLspSpecification::SemanticTokensOptions options;
+ options.range = true;
+ options.full = QJsonObject({ { u"delta"_s, true } });
+ options.legend.tokenTypes = tokenTypesList();
+ options.legend.tokenModifiers = tokenModifiersList();
+
+ serverCapabilities.capabilities.semanticTokensProvider = options;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmlls/qqmlhighlightsupport_p.h b/src/qmlls/qqmlhighlightsupport_p.h
new file mode 100644
index 0000000000..ef84b94ef3
--- /dev/null
+++ b/src/qmlls/qqmlhighlightsupport_p.h
@@ -0,0 +1,96 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLHIGHLIGHTSUPPORT_P_H
+#define QQMLHIGHLIGHTSUPPORT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qlanguageserver_p.h"
+#include "qqmlbasemodule_p.h"
+#include "qqmlcodemodel_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// We don't need these overrides as we register the request handlers in a single
+// module QQmlHighlightSupport. This is an unusual pattern because QQmlBaseModule
+// and QLanguageServerModule abstractions are designed to handle a single module
+// which has a single request handlers. That is not the case for the semanticTokens
+// module which has a one server module but also has three different handlers.
+#define HIDE_UNUSED_OVERRIDES \
+ private: \
+ QString name() const override \
+ { \
+ return {}; \
+ } \
+ void setupCapabilities(const QLspSpecification::InitializeParams &, \
+ QLspSpecification::InitializeResult &) override \
+ { \
+ }
+
+using SemanticTokensRequest = BaseRequest<QLspSpecification::SemanticTokensParams,
+ QLspSpecification::Responses::SemanticTokensResponseType>;
+
+using SemanticTokensDeltaRequest =
+ BaseRequest<QLspSpecification::SemanticTokensDeltaParams,
+ QLspSpecification::Responses::SemanticTokensDeltaResponseType>;
+
+using SemanticTokensRangeRequest =
+ BaseRequest<QLspSpecification::SemanticTokensRangeParams,
+ QLspSpecification::Responses::SemanticTokensRangeResponseType>;
+
+class SemanticTokenFullHandler : public QQmlBaseModule<SemanticTokensRequest>
+{
+public:
+ SemanticTokenFullHandler(QmlLsp::QQmlCodeModel *codeModel);
+ void process(QQmlBaseModule<SemanticTokensRequest>::RequestPointerArgument req) override;
+ void registerHandlers(QLanguageServer *, QLanguageServerProtocol *) override;
+ HIDE_UNUSED_OVERRIDES
+};
+
+class SemanticTokenDeltaHandler : public QQmlBaseModule<SemanticTokensDeltaRequest>
+{
+public:
+ SemanticTokenDeltaHandler(QmlLsp::QQmlCodeModel *codeModel);
+ void process(QQmlBaseModule<SemanticTokensDeltaRequest>::RequestPointerArgument req) override;
+ void registerHandlers(QLanguageServer *, QLanguageServerProtocol *) override;
+ HIDE_UNUSED_OVERRIDES
+};
+
+class SemanticTokenRangeHandler : public QQmlBaseModule<SemanticTokensRangeRequest>
+{
+public:
+ SemanticTokenRangeHandler(QmlLsp::QQmlCodeModel *codeModel);
+ void process(QQmlBaseModule<SemanticTokensRangeRequest>::RequestPointerArgument req) override;
+ void registerHandlers(QLanguageServer *, QLanguageServerProtocol *) override;
+ HIDE_UNUSED_OVERRIDES
+};
+
+class QQmlHighlightSupport : public QLanguageServerModule
+{
+public:
+ QQmlHighlightSupport(QmlLsp::QQmlCodeModel *codeModel);
+ QString name() const override;
+ void registerHandlers(QLanguageServer *server, QLanguageServerProtocol *protocol) override;
+ void setupCapabilities(const QLspSpecification::InitializeParams &clientInfo,
+ QLspSpecification::InitializeResult &) override;
+private:
+ SemanticTokenFullHandler m_full;
+ SemanticTokenDeltaHandler m_delta;
+ SemanticTokenRangeHandler m_range;
+};
+
+#undef HIDE_UNUSED_OVERRIDES
+
+QT_END_NAMESPACE
+
+#endif // QQMLHIGHLIGHTSUPPORT_P_H
diff --git a/src/qmlls/qqmlhover.cpp b/src/qmlls/qqmlhover.cpp
index 4f604558a3..d2acd7b5d9 100644
--- a/src/qmlls/qqmlhover.cpp
+++ b/src/qmlls/qqmlhover.cpp
@@ -1,17 +1,27 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <qqmlhover_p.h>
+#include "qqmlhover_p.h"
+#include <QtQmlLS/private/qqmllshelputils_p.h>
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(hoverLog, "qt.languageserver.hover")
QQmlHover::QQmlHover(QmlLsp::QQmlCodeModel *codeModel)
- : QQmlBaseModule(codeModel)
+ : QQmlBaseModule(codeModel), m_helpManager(std::make_unique<HelpManager>())
{
+ // if set thorugh the commandline
+ if (!codeModel->documentationRootPath().isEmpty())
+ m_helpManager->setDocumentationRootPath(codeModel->documentationRootPath());
+
+ connect(codeModel, &QmlLsp::QQmlCodeModel::documentationRootPathChanged, this, [this](const QString &path) {
+ m_helpManager->setDocumentationRootPath(path);
+ });
}
+QQmlHover::~QQmlHover() = default;
+
QString QQmlHover::name() const
{
return u"QQmlHover"_s;
@@ -31,51 +41,42 @@ void QQmlHover::setupCapabilities(
void QQmlHover::process(RequestPointerArgument request)
{
+ if (!m_helpManager) {
+ qCWarning(hoverLog)
+ << "No help manager is available, documentation hints will not function!";
+ return;
+ }
using namespace QQmlJS::Dom;
QLspSpecification::Hover result;
ResponseScopeGuard guard(result, request->m_response);
-
if (!request) {
qCWarning(hoverLog) << "No hover information is available!";
return;
}
-
const auto textDocument = request->m_parameters.textDocument;
- const auto [hoveredLine, hoveredCharacter] = request->m_parameters.position;
- qCDebug(hoverLog) << QStringLiteral("Hovered (line, col): (%1,%2)").arg(hoveredLine).arg(hoveredCharacter);
-
- const auto doc = m_codeModel->openDocumentByUrl(
- QQmlLSUtils::lspUriToQmlUrl(textDocument.uri));
-
+ const auto position = request->m_parameters.position;
+ const auto doc = m_codeModel->openDocumentByUrl(QQmlLSUtils::lspUriToQmlUrl(textDocument.uri));
DomItem file = doc.snapshot.doc.fileObject(GoTo::MostLikely);
if (!file) {
- guard.setError(QQmlLSUtilsErrorMessage{
+ guard.setError(QQmlLSUtils::ErrorMessage{
0, u"Could not find the file %1"_s.arg(doc.snapshot.doc.canonicalFilePath()) });
return;
}
- // TODO: Fetch the actual documentation or other possible infos to be shown when hovered.
- // Early return if hovered element is not identifier kind (for example, don't perform anything on paranthesis)
-
- const auto documentation = QQmlLSUtils::getDocumentationFromLocation(
- file, { hoveredLine + 1, hoveredCharacter + 1 });
- if (documentation.isEmpty()) {
+ const auto documentation = m_helpManager->documentationForItem(file, position);
+ if (!documentation.has_value()) {
qCDebug(hoverLog)
<< QStringLiteral(
"No documentation hints found for the item at (line, col): (%1,%2)")
- .arg(hoveredLine)
- .arg(hoveredCharacter);
+ .arg(position.line)
+ .arg(position.character);
return;
}
-
QLspSpecification::MarkupContent content;
-
- // TODO: This should eventually be a Markdown kind.
- // We will do post-formatting what we fetch from documentation.
- content.kind = QLspSpecification::MarkupKind::PlainText;
- content.value = documentation;
-
- result.contents = content;
+ // TODO: We need to do post-formatting what we fetch from documentation.
+ content.kind = QLspSpecification::MarkupKind::Markdown;
+ content.value = documentation.value();
+ result.contents = std::move(content);
}
QT_END_NAMESPACE
diff --git a/src/qmlls/qqmlhover_p.h b/src/qmlls/qqmlhover_p.h
index 6d3fa59c62..ba964adc8b 100644
--- a/src/qmlls/qqmlhover_p.h
+++ b/src/qmlls/qqmlhover_p.h
@@ -26,17 +26,21 @@ struct HoverRequest
QLspSpecification::Responses::HoverResponseType>
{
};
-
+class HelpManager;
class QQmlHover : public QQmlBaseModule<HoverRequest>
{
Q_OBJECT
public:
QQmlHover(QmlLsp::QQmlCodeModel *codeModel);
+ ~QQmlHover() override;
QString name() const override;
void registerHandlers(QLanguageServer *server, QLanguageServerProtocol *protocol) override;
void setupCapabilities(const QLspSpecification::InitializeParams &clientInfo,
QLspSpecification::InitializeResult &) override;
void process(RequestPointerArgument req) override;
+
+private:
+ std::unique_ptr<HelpManager> m_helpManager;
};
QT_END_NAMESPACE
diff --git a/src/qmlls/qqmllanguageserver.cpp b/src/qmlls/qqmllanguageserver.cpp
index fb711300c4..1ef142b7b5 100644
--- a/src/qmlls/qqmllanguageserver.cpp
+++ b/src/qmlls/qqmllanguageserver.cpp
@@ -67,7 +67,8 @@ QQmlLanguageServer::QQmlLanguageServer(std::function<void(const QByteArray &)> s
m_documentFormatting(&m_codeModel),
m_renameSupport(&m_codeModel),
m_rangeFormatting(&m_codeModel),
- m_hover(&m_codeModel)
+ m_hover(&m_codeModel),
+ m_highlightSupport(&m_codeModel)
{
m_server.addServerModule(this);
m_server.addServerModule(&m_textSynchronization);
@@ -81,6 +82,7 @@ QQmlLanguageServer::QQmlLanguageServer(std::function<void(const QByteArray &)> s
m_server.addServerModule(&m_renameSupport);
m_server.addServerModule(&m_rangeFormatting);
m_server.addServerModule(&m_hover);
+ m_server.addServerModule(&m_highlightSupport);
m_server.finishSetup();
qCWarning(lspServerLog) << "Did Setup";
}
diff --git a/src/qmlls/qqmllanguageserver_p.h b/src/qmlls/qqmllanguageserver_p.h
index 8da705ccb0..3347acd670 100644
--- a/src/qmlls/qqmllanguageserver_p.h
+++ b/src/qmlls/qqmllanguageserver_p.h
@@ -28,6 +28,7 @@
#include "qqmlgotodefinitionsupport_p.h"
#include "qqmlrenamesymbolsupport_p.h"
#include "qqmlhover_p.h"
+#include "qqmlhighlightsupport_p.h"
QT_BEGIN_NAMESPACE
@@ -73,6 +74,7 @@ private:
QQmlRenameSymbolSupport m_renameSupport;
QQmlRangeFormatting m_rangeFormatting;
QQmlHover m_hover;
+ QQmlHighlightSupport m_highlightSupport;
int m_returnValue = 1;
};
diff --git a/src/qmlls/qqmllscompletion.cpp b/src/qmlls/qqmllscompletion.cpp
index 8ecbcffc70..4c25b39d83 100644
--- a/src/qmlls/qqmllscompletion.cpp
+++ b/src/qmlls/qqmllscompletion.cpp
@@ -149,7 +149,7 @@ QQmlLSCompletion::suggestBindingCompletion(const DomItem &itemAtPosition, BackIn
const DomItem owner = itemAtPosition.directParent().field(Fields::left);
auto expressionType = QQmlLSUtils::resolveExpressionType(
- owner, ResolveActualTypeForFieldMemberExpression);
+ owner, QQmlLSUtils::ResolveActualTypeForFieldMemberExpression);
return expressionType ? expressionType->semanticScope : QQmlJSScope::ConstPtr{};
}();
@@ -511,13 +511,13 @@ void QQmlLSCompletion::suggestJSExpressionCompletion(const DomItem &scriptIdenti
(askForCompletionOnDot ? scriptIdentifier : scriptIdentifier.directParent())
.field(Fields::left);
auto expressionType = QQmlLSUtils::resolveExpressionType(
- owner, ResolveActualTypeForFieldMemberExpression);
+ owner, QQmlLSUtils::ResolveActualTypeForFieldMemberExpression);
if (!expressionType || !expressionType->semanticScope)
return;
nearestScope = expressionType->semanticScope;
// Use root element scope to use find the enumerations
// This should be changed when we support usages in external files
- if (expressionType->type == QmlComponentIdentifier)
+ if (expressionType->type == QQmlLSUtils::QmlComponentIdentifier)
nearestScope = owner.rootQmlObject(GoTo::MostLikely).semanticScope();
if (expressionType->name) {
// note: you only get enumeration values in qualified expressions, never alone
@@ -529,7 +529,7 @@ void QQmlLSCompletion::suggestJSExpressionCompletion(const DomItem &scriptIdenti
enumerationCompletion(nearestScope, &usedNames, result);
}
- if (expressionType->type == EnumeratorIdentifier)
+ if (expressionType->type == QQmlLSUtils::EnumeratorIdentifier)
return;
}
}
@@ -823,7 +823,8 @@ void QQmlLSCompletion::insideBindingCompletion(const DomItem &currentItem,
if (cursorAfterColon(containingBinding, positionInfo)) {
suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
- if (auto type = QQmlLSUtils::resolveExpressionType(currentItem, ResolveOwnerType)) {
+ if (auto type = QQmlLSUtils::resolveExpressionType(currentItem,
+ QQmlLSUtils::ResolveOwnerType)) {
const QStringList names = currentItem.field(Fields::name).toString().split(u'.');
const QQmlJSScope *current = resolve(type->semanticScope.get(), names);
// add type names when binding to an object type or a property with var type
@@ -895,7 +896,7 @@ void QQmlLSCompletion::insideQmlFileCompletion(const DomItem &currentItem,
Generate the snippets for let, var and const variable declarations.
*/
void QQmlLSCompletion::suggestVariableDeclarationStatementCompletion(
- BackInsertIterator result, QQmlLSUtilsAppendOption option) const
+ BackInsertIterator result, AppendOption option) const
{
// let/var/const statement
for (auto view : std::array<QUtf8StringView, 3>{ "let", "var", "const" }) {
@@ -1104,7 +1105,7 @@ void QQmlLSCompletion::insideForStatementCompletion(const DomItem &parentForCont
if (betweenLocations(leftParenthesis, positionInfo, firstSemicolon)) {
suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
suggestVariableDeclarationStatementCompletion(result,
- QQmlLSUtilsAppendOption::AppendNothing);
+ AppendOption::AppendNothing);
return;
}
if (betweenLocations(firstSemicolon, positionInfo, secondSemicolon)
diff --git a/src/qmlls/qqmllscompletion_p.h b/src/qmlls/qqmllscompletion_p.h
index a31d3daebc..a371fd0315 100644
--- a/src/qmlls/qqmllscompletion_p.h
+++ b/src/qmlls/qqmllscompletion_p.h
@@ -31,12 +31,14 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QQmlLSCompletionLog)
-enum QQmlLSUtilsAppendOption { AppendSemicolon, AppendNothing };
class QQmlLSCompletion
{
using DomItem = QQmlJS::Dom::DomItem;
public:
+ enum class ImportCompletionType { None, Module, Version };
+ enum AppendOption { AppendSemicolon, AppendNothing };
+
QQmlLSCompletion(const QFactoryLoader &pluginLoader);
using CompletionItem = QLspSpecification::CompletionItem;
@@ -84,7 +86,7 @@ private:
void suggestJSStatementCompletion(const DomItem &currentItem, BackInsertIterator it) const;
void suggestCaseAndDefaultStatementCompletion(BackInsertIterator it) const;
void suggestVariableDeclarationStatementCompletion(
- BackInsertIterator it, QQmlLSUtilsAppendOption option = AppendSemicolon) const;
+ BackInsertIterator it, AppendOption option = AppendSemicolon) const;
void suggestJSExpressionCompletion(const DomItem &context, BackInsertIterator it) const;
diff --git a/src/qmlls/qqmllshelpplugininterface.cpp b/src/qmlls/qqmllshelpplugininterface.cpp
new file mode 100644
index 0000000000..62944d69e0
--- /dev/null
+++ b/src/qmlls/qqmllshelpplugininterface.cpp
@@ -0,0 +1,4 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmllshelpplugininterface_p.h"
diff --git a/src/qmlls/qqmllshelpplugininterface_p.h b/src/qmlls/qqmllshelpplugininterface_p.h
new file mode 100644
index 0000000000..280d7c3e5d
--- /dev/null
+++ b/src/qmlls/qqmllshelpplugininterface_p.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLLSHELPPLUGININTERFACE_H
+#define QQMLLSHELPPLUGININTERFACE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qstring.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qobject.h>
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlLSHelpProviderBase
+{
+public:
+ struct DocumentLink
+ {
+ QUrl url;
+ QString title;
+ };
+
+public:
+ virtual ~QQmlLSHelpProviderBase() = default;
+ virtual bool registerDocumentation(const QString &documentationFileName) = 0;
+ [[nodiscard]] virtual QByteArray fileData(const QUrl &url) const = 0;
+ [[nodiscard]] virtual std::vector<DocumentLink> documentsForIdentifier(const QString &id) const = 0;
+ [[nodiscard]] virtual std::vector<DocumentLink>
+ documentsForIdentifier(const QString &id, const QString &filterName) const = 0;
+ [[nodiscard]] virtual std::vector<DocumentLink> documentsForKeyword(const QString &keyword) const = 0;
+ [[nodiscard]] virtual std::vector<DocumentLink>
+ documentsForKeyword(const QString &keyword, const QString &filterName) const = 0;
+ [[nodiscard]] virtual QStringList registeredNamespaces() const = 0;
+ [[nodiscard]] virtual QString error() const = 0;
+};
+
+class QQmlLSHelpPluginInterface
+{
+public:
+ QQmlLSHelpPluginInterface() = default;
+ virtual ~QQmlLSHelpPluginInterface() = default;
+ Q_DISABLE_COPY_MOVE(QQmlLSHelpPluginInterface)
+
+ virtual std::unique_ptr<QQmlLSHelpProviderBase> initialize(const QString &collectionFile,
+ QObject *parent) = 0;
+};
+
+#define QQmlLSHelpPluginInterface_iid "org.qt-project.Qt.QmlLS.HelpPlugin/1.0"
+Q_DECLARE_INTERFACE(QQmlLSHelpPluginInterface, QQmlLSHelpPluginInterface_iid)
+
+QT_END_NAMESPACE
+
+#endif // QQMLLSHELPPLUGININTERFACE_H
diff --git a/src/qmlls/qqmllshelputils.cpp b/src/qmlls/qqmllshelputils.cpp
new file mode 100644
index 0000000000..688b2c63d9
--- /dev/null
+++ b/src/qmlls/qqmllshelputils.cpp
@@ -0,0 +1,254 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmllshelputils_p.h"
+
+#include <QtQmlLS/private/qqmllsutils_p.h>
+#include <QtCore/private/qfactoryloader_p.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qdir.h>
+#include <QtQmlCompiler/private/qqmljstyperesolver_p.h>
+#include <optional>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(QQmlLSHelpUtilsLog, "qt.languageserver.helpUtils")
+
+using namespace QQmlJS::Dom;
+
+static QStringList documentationFiles(const QString &qtInstallationPath)
+{
+ QStringList result;
+ QDirIterator dirIterator(qtInstallationPath, QStringList{ "*.qch"_L1 }, QDir::Files);
+ while (dirIterator.hasNext()) {
+ const auto fileInfo = dirIterator.nextFileInfo();
+ result << fileInfo.absoluteFilePath();
+ }
+ return result;
+}
+
+HelpManager::HelpManager()
+{
+ const QFactoryLoader pluginLoader(QQmlLSHelpPluginInterface_iid, u"/help"_s);
+ const auto keys = pluginLoader.metaDataKeys();
+ for (qsizetype i = 0; i < keys.size(); ++i) {
+ auto instance = qobject_cast<QQmlLSHelpPluginInterface *>(pluginLoader.instance(i));
+ if (instance) {
+ m_helpPlugin =
+ instance->initialize(QDir::tempPath() + "/collectionFile.qhc"_L1, nullptr);
+ break;
+ }
+ }
+}
+
+void HelpManager::setDocumentationRootPath(const QString &path)
+{
+ if (m_docRootPath == path)
+ return;
+ m_docRootPath = path;
+
+ const auto foundQchFiles = documentationFiles(path);
+ if (foundQchFiles.isEmpty()) {
+ qCWarning(QQmlLSHelpUtilsLog)
+ << "No documentation files found in the Qt doc installation path: " << path;
+ return;
+ }
+
+ return registerDocumentations(foundQchFiles);
+}
+
+QString HelpManager::documentationRootPath() const
+{
+ return m_docRootPath;
+}
+
+void HelpManager::registerDocumentations(const QStringList &docs) const
+{
+ if (!m_helpPlugin)
+ return;
+ std::for_each(docs.cbegin(), docs.cend(),
+ [this](const auto &file) { m_helpPlugin->registerDocumentation(file); });
+}
+
+std::optional<QByteArray> HelpManager::extractDocumentation(const DomItem &item) const
+{
+ if (item.internalKind() == DomType::ScriptIdentifierExpression) {
+ const auto resolvedType =
+ QQmlLSUtils::resolveExpressionType(item, QQmlLSUtils::ResolveOwnerType);
+ if (!resolvedType)
+ return std::nullopt;
+
+ return extractDocumentationForIdentifiers(item, resolvedType.value());
+ } else {
+ return extractDocumentationForDomElements(item);
+ }
+
+ Q_UNREACHABLE_RETURN(std::nullopt);
+}
+
+std::optional<QByteArray>
+HelpManager::extractDocumentationForIdentifiers(const DomItem &item,
+ QQmlLSUtils::ExpressionType expr) const
+{
+ const auto qmlFile = item.containingFile().as<QmlFile>();
+ if (!qmlFile)
+ return std::nullopt;
+ const auto links = collectDocumentationLinks(expr.semanticScope, qmlFile->typeResolver(),
+ expr.name.value());
+ switch (expr.type) {
+ case QQmlLSUtils::QmlObjectIdIdentifier:
+ case QQmlLSUtils::JavaScriptIdentifier:
+ case QQmlLSUtils::GroupedPropertyIdentifier:
+ case QQmlLSUtils::PropertyIdentifier: {
+ ExtractDocumentation extractor(DomType::PropertyDefinition);
+ return tryExtract(extractor, links, expr.name.value());
+ }
+ case QQmlLSUtils::PropertyChangedSignalIdentifier:
+ case QQmlLSUtils::PropertyChangedHandlerIdentifier:
+ case QQmlLSUtils::SignalIdentifier:
+ case QQmlLSUtils::SignalHandlerIdentifier:
+ case QQmlLSUtils::MethodIdentifier: {
+ ExtractDocumentation extractor(DomType::MethodInfo);
+ return tryExtract(extractor, links, expr.name.value());
+ }
+ case QQmlLSUtils::SingletonIdentifier:
+ case QQmlLSUtils::AttachedTypeIdentifier:
+ case QQmlLSUtils::QmlComponentIdentifier: {
+ ExtractDocumentation extractor(DomType::QmlObject);
+ return tryExtract(extractor, links, expr.name.value());
+ }
+
+ // Not implemented yet
+ case QQmlLSUtils::EnumeratorIdentifier:
+ case QQmlLSUtils::EnumeratorValueIdentifier:
+ default:
+ qCDebug(QQmlLSHelpUtilsLog)
+ << "Documentation extraction for" << expr.name.value() << "was not implemented";
+ return std::nullopt;
+ }
+ Q_UNREACHABLE_RETURN(std::nullopt);
+}
+
+std::optional<QByteArray> HelpManager::extractDocumentationForDomElements(const DomItem &item) const
+{
+ const auto qmlFile = item.containingFile().as<QmlFile>();
+ if (!qmlFile)
+ return std::nullopt;
+
+ const auto name = item.field(Fields::name).value().toString();
+ std::vector<QQmlLSHelpProviderBase::DocumentLink> links;
+ switch (item.internalKind()) {
+ case DomType::QmlObject: {
+ links = collectDocumentationLinks(item.nearestSemanticScope(), qmlFile->typeResolver(),
+ name);
+ break;
+ }
+ case DomType::PropertyDefinition: {
+ const auto scope =
+ QQmlLSUtils::findDefiningScopeForProperty(item.nearestSemanticScope(), name);
+ links = collectDocumentationLinks(scope, qmlFile->typeResolver(), name);
+ break;
+ }
+ case DomType::Binding: {
+ const auto scope =
+ QQmlLSUtils::findDefiningScopeForBinding(item.nearestSemanticScope(), name);
+ links = collectDocumentationLinks(scope, qmlFile->typeResolver(), name);
+ break;
+ }
+ case DomType::MethodInfo: {
+ const auto scope =
+ QQmlLSUtils::findDefiningScopeForMethod(item.nearestSemanticScope(), name);
+ links = collectDocumentationLinks(scope, qmlFile->typeResolver(), name);
+ break;
+ }
+ default:
+ qCDebug(QQmlLSHelpUtilsLog)
+ << item.internalKindStr() << "was not implemented for documentation extraction";
+ return std::nullopt;
+ }
+
+ ExtractDocumentation extractor(item.internalKind());
+ return tryExtract(extractor, links, name);
+}
+
+std::optional<QByteArray>
+HelpManager::tryExtract(ExtractDocumentation &extractor,
+ const std::vector<QQmlLSHelpProviderBase::DocumentLink> &links,
+ const QString &name) const
+{
+ if (!m_helpPlugin)
+ return std::nullopt;
+
+ for (auto &&link : links) {
+ const auto fileData = m_helpPlugin->fileData(link.url);
+ if (fileData.isEmpty()) {
+ qCDebug(QQmlLSHelpUtilsLog) << "No documentation found for" << link.url;
+ continue;
+ }
+ const auto &documentation = extractor.execute(QString::fromUtf8(fileData), name,
+ HtmlExtractor::ExtractionMode::Simplified);
+ if (documentation.isEmpty())
+ continue;
+ return documentation.toUtf8();
+ }
+
+ return std::nullopt;
+}
+
+std::optional<QByteArray>
+HelpManager::documentationForItem(const DomItem &file, QLspSpecification::Position position) const
+{
+ if (!m_helpPlugin)
+ return std::nullopt;
+
+ if (m_helpPlugin->registeredNamespaces().empty())
+ return std::nullopt;
+
+ std::optional<QByteArray> result;
+ const auto [line, character] = position;
+ const auto itemLocations = QQmlLSUtils::itemsFromTextLocation(file, line, character);
+
+ // Process found item's internalKind and fetch its documentation.
+ for (const auto &entry : itemLocations) {
+ result = extractDocumentation(entry.domItem);
+ if (result.has_value())
+ break;
+ }
+
+ return result;
+}
+
+/*
+ * Returns the list of potential documentation links for the given item.
+ * A keyword is not necessarily a unique name, so we need to find the scope where
+ * the keyword is defined. If the item is a property, method or binding, it will
+ * search for the defining scope and return the documentation links by looking at
+ * the imported names. If the item is a QmlObject, it will return the documentation
+ * links for qmlobject name.
+ */
+std::vector<QQmlLSHelpProviderBase::DocumentLink>
+HelpManager::collectDocumentationLinks(QQmlJSScope::ConstPtr scope,
+ std::shared_ptr<QQmlJSTypeResolver> typeResolver,
+ const QString &name) const
+{
+ if (!m_helpPlugin)
+ return {};
+ const auto potentialDocumentationLinks =
+ [this](QQmlJSScope::ConstPtr scope, std::shared_ptr<QQmlJSTypeResolver> typeResolver)
+ -> std::vector<QQmlLSHelpProviderBase::DocumentLink> {
+ if (!scope || !typeResolver)
+ return {};
+
+ std::vector<QQmlLSHelpProviderBase::DocumentLink> links;
+ const auto docLinks = m_helpPlugin->documentsForKeyword(typeResolver->nameForType(scope));
+ std::copy(docLinks.cbegin(), docLinks.cend(), std::back_inserter(links));
+ return links;
+ };
+
+ // If the scope is not found for the defined scope, return all the links related to this name.
+ const auto result = potentialDocumentationLinks(scope, typeResolver);
+ return result.empty() ? m_helpPlugin->documentsForKeyword(name) : result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmlls/qqmllshelputils_p.h b/src/qmlls/qqmllshelputils_p.h
new file mode 100644
index 0000000000..70ead5e2e8
--- /dev/null
+++ b/src/qmlls/qqmllshelputils_p.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLLSHELPUTILS_P_H
+#define QQMLLSHELPUTILS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQmlLS/private/qqmllshelpplugininterface_p.h>
+#include <QtQmlLS/private/qqmllsutils_p.h>
+#include <QtQmlDom/private/qqmldomtop_p.h>
+#include <QtQmlLS/private/qdochtmlparser_p.h>
+#include <QtLanguageServer/private/qlanguageserverspectypes_p.h>
+
+#include <vector>
+#include <string>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QQmlLSHelpUtilsLog);
+
+using namespace QQmlJS::Dom;
+
+class HelpManager final
+{
+public:
+ HelpManager();
+ void setDocumentationRootPath(const QString &path);
+ [[nodiscard]] QString documentationRootPath() const;
+ [[nodiscard]] std::optional<QByteArray> documentationForItem(const DomItem &file,
+ QLspSpecification::Position position) const;
+
+private:
+ [[nodiscard]] std::optional<QByteArray> extractDocumentationForIdentifiers(const DomItem &item,
+ QQmlLSUtils::ExpressionType) const;
+ [[nodiscard]] std::optional<QByteArray> extractDocumentationForDomElements(const DomItem &item) const;
+ [[nodiscard]] std::optional<QByteArray> extractDocumentation(const DomItem &item) const;
+ [[nodiscard]] std::optional<QByteArray> tryExtract(ExtractDocumentation &extractor,
+ const std::vector<QQmlLSHelpProviderBase::DocumentLink> &links,
+ const QString &name) const;
+ [[nodiscard]] std::vector<QQmlLSHelpProviderBase::DocumentLink> collectDocumentationLinks(QQmlJSScope::ConstPtr scope,
+ std::shared_ptr<QQmlJSTypeResolver> typeResolver,
+ const QString &name) const;
+ void registerDocumentations(const QStringList &docs) const;
+ std::unique_ptr<QQmlLSHelpProviderBase> m_helpPlugin;
+ QString m_docRootPath;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLLSHELPUTILS_P_H
diff --git a/src/qmlls/qqmllsutils.cpp b/src/qmlls/qqmllsutils.cpp
index bc9f21d7b9..70f250b1c3 100644
--- a/src/qmlls/qqmllsutils.cpp
+++ b/src/qmlls/qqmllsutils.cpp
@@ -25,7 +25,6 @@
#include <utility>
#include <variant>
-using namespace QLspSpecification;
using namespace QQmlJS::Dom;
using namespace Qt::StringLiterals;
@@ -33,7 +32,8 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(QQmlLSUtilsLog, "qt.languageserver.utils")
-QString QQmlLSUtils::qualifiersFrom(const DomItem &el)
+namespace QQmlLSUtils {
+QString qualifiersFrom(const DomItem &el)
{
const bool isAccess = QQmlLSUtils::isFieldMemberAccess(el);
if (!isAccess && !QQmlLSUtils::isFieldMemberExpression(el))
@@ -55,7 +55,7 @@ QString QQmlLSUtils::qualifiersFrom(const DomItem &el)
\internal
Helper to check if item is a Field Member Expression \c {<someExpression>.propertyName}.
*/
-bool QQmlLSUtils::isFieldMemberExpression(const DomItem &item)
+bool isFieldMemberExpression(const DomItem &item)
{
return item.internalKind() == DomType::ScriptBinaryExpression
&& item.field(Fields::operation).value().toInteger()
@@ -67,7 +67,7 @@ bool QQmlLSUtils::isFieldMemberExpression(const DomItem &item)
Helper to check if item is a Field Member Access \c memberAccess in
\c {<someExpression>.memberAccess}.
*/
-bool QQmlLSUtils::isFieldMemberAccess(const DomItem &item)
+bool isFieldMemberAccess(const DomItem &item)
{
auto parent = item.directParent();
if (!isFieldMemberExpression(parent))
@@ -86,7 +86,7 @@ bool QQmlLSUtils::isFieldMemberAccess(const DomItem &item)
FieldMemberExpression stopAtChild, or before processing a ScriptIdentifierExpression stopAtChild.
No early exits if stopAtChild is default constructed.
*/
-QStringList QQmlLSUtils::fieldMemberExpressionBits(const DomItem &item, const DomItem &stopAtChild)
+QStringList fieldMemberExpressionBits(const DomItem &item, const DomItem &stopAtChild)
{
const bool isAccess = isFieldMemberAccess(item);
const bool isExpression = isFieldMemberExpression(item);
@@ -127,12 +127,12 @@ QStringList QQmlLSUtils::fieldMemberExpressionBits(const DomItem &item, const Do
\sa QQmlLSUtils::qmlUriToLspUrl
*/
-QByteArray QQmlLSUtils::lspUriToQmlUrl(const QByteArray &uri)
+QByteArray lspUriToQmlUrl(const QByteArray &uri)
{
return uri;
}
-QByteArray QQmlLSUtils::qmlUrlToLspUri(const QByteArray &url)
+QByteArray qmlUrlToLspUri(const QByteArray &url)
{
return url;
}
@@ -146,10 +146,10 @@ QByteArray QQmlLSUtils::qmlUrlToLspUri(const QByteArray &url)
contains startLine, startColumn, endLine and endColumn, which must be computed from the actual
qml code.
*/
-QLspSpecification::Range QQmlLSUtils::qmlLocationToLspLocation(const QString &code,
- QQmlJS::SourceLocation qmlLocation)
+QLspSpecification::Range qmlLocationToLspLocation(const QString &code,
+ QQmlJS::SourceLocation qmlLocation)
{
- Range range;
+ QLspSpecification::Range range;
range.start.line = qmlLocation.startLine - 1;
range.start.character = qmlLocation.startColumn - 1;
@@ -169,7 +169,7 @@ QLspSpecification::Range QQmlLSUtils::qmlLocationToLspLocation(const QString &co
\sa QQmlLSUtils::textRowAndColumnFrom
*/
-qsizetype QQmlLSUtils::textOffsetFrom(const QString &text, int row, int column)
+qsizetype textOffsetFrom(const QString &text, int row, int column)
{
int targetLine = row;
qsizetype i = 0;
@@ -206,7 +206,7 @@ qsizetype QQmlLSUtils::textOffsetFrom(const QString &text, int row, int column)
\sa QQmlLSUtils::textOffsetFrom
*/
-QQmlLSUtilsTextPosition QQmlLSUtils::textRowAndColumnFrom(const QString &text, qsizetype offset)
+TextPosition textRowAndColumnFrom(const QString &text, qsizetype offset)
{
int row = 0;
int column = 0;
@@ -226,13 +226,11 @@ QQmlLSUtilsTextPosition QQmlLSUtils::textRowAndColumnFrom(const QString &text, q
return { row, column };
}
-static QList<QQmlLSUtilsItemLocation>::const_iterator
-handlePropertyDefinitionAndBindingOverlap(const QList<QQmlLSUtilsItemLocation> &items,
- qsizetype offsetInFile)
+static QList<ItemLocation>::const_iterator
+handlePropertyDefinitionAndBindingOverlap(const QList<ItemLocation> &items, qsizetype offsetInFile)
{
auto smallest = std::min_element(
- items.begin(), items.end(),
- [](const QQmlLSUtilsItemLocation &a, const QQmlLSUtilsItemLocation &b) {
+ items.begin(), items.end(), [](const ItemLocation &a, const ItemLocation &b) {
return a.fileLocation->info().fullRegion.length
< b.fileLocation->info().fullRegion.length;
});
@@ -250,8 +248,7 @@ handlePropertyDefinitionAndBindingOverlap(const QList<QQmlLSUtilsItemLocation> &
// get the smallest property definition to avoid getting the property definition that the
// current QmlObject is getting bound to!
auto smallestPropertyDefinition = std::min_element(
- items.begin(), items.end(),
- [](const QQmlLSUtilsItemLocation &a, const QQmlLSUtilsItemLocation &b) {
+ items.begin(), items.end(), [](const ItemLocation &a, const ItemLocation &b) {
// make property definition smaller to avoid getting smaller items that are not
// property definitions
const bool aIsPropertyDefinition =
@@ -279,8 +276,8 @@ handlePropertyDefinitionAndBindingOverlap(const QList<QQmlLSUtilsItemLocation> &
return smallest;
}
-static QList<QQmlLSUtilsItemLocation>
-filterItemsFromTextLocation(const QList<QQmlLSUtilsItemLocation> &items, qsizetype offsetInFile)
+static QList<ItemLocation> filterItemsFromTextLocation(const QList<ItemLocation> &items,
+ qsizetype offsetInFile)
{
if (items.size() < 2)
return items;
@@ -291,7 +288,7 @@ filterItemsFromTextLocation(const QList<QQmlLSUtilsItemLocation> &items, qsizety
// "contain" everything from their first-appearing to last-appearing property (e.g. also
// other stuff in between those two properties).
- QList<QQmlLSUtilsItemLocation> filteredItems;
+ QList<ItemLocation> filteredItems;
auto smallest = handlePropertyDefinitionAndBindingOverlap(items, offsetInFile);
@@ -323,17 +320,16 @@ filterItemsFromTextLocation(const QList<QQmlLSUtilsItemLocation> &items, qsizety
If line and character point between two objects, two objects might be returned.
If line and character point to whitespace, it might return an inner node of the QmlDom-Tree.
*/
-QList<QQmlLSUtilsItemLocation> QQmlLSUtils::itemsFromTextLocation(const DomItem &file, int line,
- int character)
+QList<ItemLocation> itemsFromTextLocation(const DomItem &file, int line, int character)
{
- QList<QQmlLSUtilsItemLocation> itemsFound;
+ QList<ItemLocation> itemsFound;
std::shared_ptr<QmlFile> filePtr = file.ownerAs<QmlFile>();
if (!filePtr)
return itemsFound;
FileLocations::Tree t = filePtr->fileLocationsTree();
Q_ASSERT(t);
QString code = filePtr->code(); // do something more advanced wrt to changes wrt to this->code?
- QList<QQmlLSUtilsItemLocation> toDo;
+ QList<ItemLocation> toDo;
qsizetype targetPos = textOffsetFrom(code, line, character);
Q_ASSERT(targetPos >= 0);
auto containsTarget = [targetPos](QQmlJS::SourceLocation l) {
@@ -344,13 +340,13 @@ QList<QQmlLSUtilsItemLocation> QQmlLSUtils::itemsFromTextLocation(const DomItem
}
};
if (containsTarget(t->info().fullRegion)) {
- QQmlLSUtilsItemLocation loc;
+ ItemLocation loc;
loc.domItem = file;
loc.fileLocation = t;
toDo.append(loc);
}
while (!toDo.isEmpty()) {
- QQmlLSUtilsItemLocation iLoc = toDo.last();
+ ItemLocation iLoc = toDo.last();
toDo.removeLast();
bool inParentButOutsideChildren = true;
@@ -361,7 +357,7 @@ QList<QQmlLSUtilsItemLocation> QQmlLSUtils::itemsFromTextLocation(const DomItem
Q_ASSERT(subLoc);
if (containsTarget(subLoc->info().fullRegion)) {
- QQmlLSUtilsItemLocation subItem;
+ ItemLocation subItem;
subItem.domItem = iLoc.domItem.path(it.key());
if (!subItem.domItem) {
qCDebug(QQmlLSUtilsLog)
@@ -390,7 +386,7 @@ QList<QQmlLSUtilsItemLocation> QQmlLSUtils::itemsFromTextLocation(const DomItem
return filtered;
}
-DomItem QQmlLSUtils::baseObject(const DomItem &object)
+DomItem baseObject(const DomItem &object)
{
DomItem prototypes;
DomItem qmlObject = object.qmlObject();
@@ -417,10 +413,9 @@ DomItem QQmlLSUtils::baseObject(const DomItem &object)
return base;
}
-static std::optional<QQmlLSUtilsLocation> locationFromDomItem(const DomItem &item,
- FileLocationRegion region)
+static std::optional<Location> locationFromDomItem(const DomItem &item, FileLocationRegion region)
{
- QQmlLSUtilsLocation location;
+ Location location;
location.filename = item.canonicalFilePath();
auto tree = FileLocations::treeOf(item);
@@ -446,7 +441,7 @@ static std::optional<QQmlLSUtilsLocation> locationFromDomItem(const DomItem &ite
For a \c Methodparameter, return the location of the type of the parameter.
Otherwise, return std::nullopt.
*/
-std::optional<QQmlLSUtilsLocation> QQmlLSUtils::findTypeDefinitionOf(const DomItem &object)
+std::optional<Location> findTypeDefinitionOf(const DomItem &object)
{
DomItem typeDefinition;
@@ -524,18 +519,18 @@ std::optional<QQmlLSUtilsLocation> QQmlLSUtils::findTypeDefinitionOf(const DomIt
break;
}
- auto scope = QQmlLSUtils::resolveExpressionType(
- object, QQmlLSUtilsResolveOptions::ResolveActualTypeForFieldMemberExpression);
+ auto scope = resolveExpressionType(
+ object, ResolveOptions::ResolveActualTypeForFieldMemberExpression);
if (!scope)
return {};
if (scope->type == QmlObjectIdIdentifier) {
- return QQmlLSUtilsLocation{ scope->semanticScope->filePath(),
- scope->semanticScope->sourceLocation() };
+ return Location{ scope->semanticScope->filePath(),
+ scope->semanticScope->sourceLocation() };
}
- typeDefinition = QQmlLSUtils::sourceLocationToDomItem(
- object.containingFile(), scope->semanticScope->sourceLocation());
+ typeDefinition = sourceLocationToDomItem(object.containingFile(),
+ scope->semanticScope->sourceLocation());
return locationFromDomItem(typeDefinition.component(),
FileLocationRegion::IdentifierRegion);
}
@@ -602,7 +597,7 @@ struct SignalOrProperty
or handler.
*/
QString name;
- QQmlLSUtilsIdentifierType type;
+ IdentifierType type;
};
/*!
@@ -716,10 +711,12 @@ static QStringList namesOfPossibleUsages(const QString &name,
}
template<typename Predicate>
-QQmlJSScope::ConstPtr findDefiningScopeIf(QQmlJSScope::ConstPtr referrerScope, Predicate &&check)
+QQmlJSScope::ConstPtr findDefiningScopeIf(
+ const QQmlJSScope::ConstPtr &referrerScope, Predicate &&check)
{
QQmlJSScope::ConstPtr result;
- QQmlJSUtils::searchBaseAndExtensionTypes(referrerScope, [&](QQmlJSScope::ConstPtr scope) {
+ QQmlJSUtils::searchBaseAndExtensionTypes(
+ referrerScope, [&](const QQmlJSScope::ConstPtr &scope) {
if (check(scope)) {
result = scope;
return true;
@@ -737,7 +734,7 @@ QQmlJSScope::ConstPtr findDefiningScopeIf(QQmlJSScope::ConstPtr referrerScope, P
Starts looking for the name starting from the given scope and traverse through base and
extension types.
*/
-static QQmlJSScope::ConstPtr findDefiningScopeForProperty(QQmlJSScope::ConstPtr referrerScope,
+QQmlJSScope::ConstPtr findDefiningScopeForProperty(QQmlJSScope::ConstPtr referrerScope,
const QString &nameToCheck)
{
return findDefiningScopeIf(referrerScope, [&nameToCheck](const QQmlJSScope::ConstPtr &scope) {
@@ -751,7 +748,7 @@ See also findDefiningScopeForProperty().
Special case: you can also bind to a signal handler.
*/
-static QQmlJSScope::ConstPtr findDefiningScopeForBinding(QQmlJSScope::ConstPtr referrerScope,
+QQmlJSScope::ConstPtr findDefiningScopeForBinding(QQmlJSScope::ConstPtr referrerScope,
const QString &nameToCheck)
{
return findDefiningScopeIf(referrerScope, [&nameToCheck](const QQmlJSScope::ConstPtr &scope) {
@@ -763,7 +760,7 @@ static QQmlJSScope::ConstPtr findDefiningScopeForBinding(QQmlJSScope::ConstPtr r
\internal
See also findDefiningScopeForProperty().
*/
-static QQmlJSScope::ConstPtr findDefiningScopeForMethod(QQmlJSScope::ConstPtr referrerScope,
+QQmlJSScope::ConstPtr findDefiningScopeForMethod(QQmlJSScope::ConstPtr referrerScope,
const QString &nameToCheck)
{
return findDefiningScopeIf(referrerScope, [&nameToCheck](const QQmlJSScope::ConstPtr &scope) {
@@ -775,7 +772,7 @@ static QQmlJSScope::ConstPtr findDefiningScopeForMethod(QQmlJSScope::ConstPtr re
\internal
See also findDefiningScopeForProperty().
*/
-static QQmlJSScope::ConstPtr findDefiningScopeForEnumeration(QQmlJSScope::ConstPtr referrerScope,
+QQmlJSScope::ConstPtr findDefiningScopeForEnumeration(QQmlJSScope::ConstPtr referrerScope,
const QString &nameToCheck)
{
return findDefiningScopeIf(referrerScope, [&nameToCheck](const QQmlJSScope::ConstPtr &scope) {
@@ -787,7 +784,7 @@ static QQmlJSScope::ConstPtr findDefiningScopeForEnumeration(QQmlJSScope::ConstP
\internal
See also findDefiningScopeForProperty().
*/
-static QQmlJSScope::ConstPtr findDefiningScopeForEnumerationKey(QQmlJSScope::ConstPtr referrerScope,
+QQmlJSScope::ConstPtr findDefiningScopeForEnumerationKey(QQmlJSScope::ConstPtr referrerScope,
const QString &nameToCheck)
{
return findDefiningScopeIf(referrerScope, [&nameToCheck](const QQmlJSScope::ConstPtr &scope) {
@@ -817,38 +814,41 @@ static FieldFilter filterForFindUsages()
return filter;
};
-static void findUsagesOfNonJSIdentifiers(const DomItem &item, const QString &name,
- QList<QQmlLSUtilsLocation> &result)
+static void findUsagesOfNonJSIdentifiers(const DomItem &item, const QString &name, Usages &result)
{
- const auto expressionType = QQmlLSUtils::resolveExpressionType(item, ResolveOwnerType);
+ const auto expressionType = resolveExpressionType(item, ResolveOwnerType);
if (!expressionType)
return;
+ // for Qml file components: add their filename as an usage for the renaming operation
+ if (expressionType->type == QmlComponentIdentifier
+ && !expressionType->semanticScope->isInlineComponent()) {
+ result.appendFilenameUsage(expressionType->semanticScope->filePath());
+ }
+
const QStringList namesToCheck = namesOfPossibleUsages(name, item, expressionType->semanticScope);
- const auto addLocationIfTypeMatchesTarget = [&result,
- &expressionType](const DomItem &toBeResolved,
- FileLocationRegion subRegion) {
- const auto currentType = QQmlLSUtils::resolveExpressionType(
- toBeResolved, QQmlLSUtilsResolveOptions::ResolveOwnerType);
- if (!currentType)
- return;
-
- const QQmlJSScope::ConstPtr target = expressionType->semanticScope;
- const QQmlJSScope::ConstPtr current = currentType->semanticScope;
- if (target == current) {
- auto tree = FileLocations::treeOf(toBeResolved);
- QQmlJS::SourceLocation sourceLocation;
-
- sourceLocation = FileLocations::region(tree, subRegion);
- if (!sourceLocation.isValid())
- return;
-
- QQmlLSUtilsLocation location{ toBeResolved.canonicalFilePath(), sourceLocation };
- if (!result.contains(location))
- result.append(location);
- }
- };
+ const auto addLocationIfTypeMatchesTarget =
+ [&result, &expressionType](const DomItem &toBeResolved, FileLocationRegion subRegion) {
+ const auto currentType =
+ resolveExpressionType(toBeResolved, ResolveOptions::ResolveOwnerType);
+ if (!currentType)
+ return;
+
+ const QQmlJSScope::ConstPtr target = expressionType->semanticScope;
+ const QQmlJSScope::ConstPtr current = currentType->semanticScope;
+ if (target == current) {
+ auto tree = FileLocations::treeOf(toBeResolved);
+ QQmlJS::SourceLocation sourceLocation;
+
+ sourceLocation = FileLocations::region(tree, subRegion);
+ if (!sourceLocation.isValid())
+ return;
+
+ Location location{ toBeResolved.canonicalFilePath(), sourceLocation };
+ result.appendUsage(location);
+ }
+ };
auto findUsages = [&addLocationIfTypeMatchesTarget, &name,
&namesToCheck](Path, const DomItem &current, bool) -> bool {
@@ -923,8 +923,8 @@ static void findUsagesOfNonJSIdentifiers(const DomItem &item, const QString &nam
}
}
-static QQmlLSUtilsLocation locationFromJSIdentifierDefinition(const DomItem &definitionOfItem,
- const QString &name)
+static Location locationFromJSIdentifierDefinition(const DomItem &definitionOfItem,
+ const QString &name)
{
Q_ASSERT_X(!definitionOfItem.semanticScope().isNull()
&& definitionOfItem.semanticScope()->ownJSIdentifier(name).has_value(),
@@ -934,12 +934,11 @@ static QQmlLSUtilsLocation locationFromJSIdentifierDefinition(const DomItem &def
QQmlJS::SourceLocation location =
definitionOfItem.semanticScope()->ownJSIdentifier(name).value().location;
- QQmlLSUtilsLocation result = { definitionOfItem.canonicalFilePath(), location };
+ Location result = { definitionOfItem.canonicalFilePath(), location };
return result;
}
-static void findUsagesHelper(
- const DomItem &item, const QString &name, QList<QQmlLSUtilsLocation> &result)
+static void findUsagesHelper(const DomItem &item, const QString &name, Usages &result)
{
qCDebug(QQmlLSUtilsLog) << "Looking for JS identifier with name" << name;
DomItem definitionOfItem = findJSIdentifierDefinition(item, name);
@@ -965,9 +964,9 @@ static void findUsagesHelper(
}
const QQmlJS::SourceLocation location = fileLocation->info().fullRegion;
const QString fileName = item.canonicalFilePath();
- result.append({ fileName, location });
+ result.appendUsage({ fileName, location });
return true;
- } else if (QQmlJSScope::ConstPtr scope = item.semanticScope();
+ } else if (const QQmlJSScope::ConstPtr scope = item.semanticScope();
scope && scope->ownJSIdentifier(name)) {
// current JS identifier has been redefined, do not visit children
return false;
@@ -976,15 +975,13 @@ static void findUsagesHelper(
},
emptyChildrenVisitor, filterForFindUsages());
- const QQmlLSUtilsLocation definition =
- locationFromJSIdentifierDefinition(definitionOfItem, name);
- if (!result.contains(definition))
- result.append(definition);
+ const Location definition = locationFromJSIdentifierDefinition(definitionOfItem, name);
+ result.appendUsage(definition);
}
-QList<QQmlLSUtilsLocation> QQmlLSUtils::findUsagesOf(const DomItem &item)
+Usages findUsagesOf(const DomItem &item)
{
- QList<QQmlLSUtilsLocation> result;
+ Usages result;
switch (item.internalKind()) {
case DomType::ScriptIdentifierExpression: {
@@ -1022,30 +1019,32 @@ QList<QQmlLSUtilsLocation> QQmlLSUtils::findUsagesOf(const DomItem &item)
return result;
}
- std::sort(result.begin(), result.end());
+ result.sort();
if (QQmlLSUtilsLog().isDebugEnabled()) {
- qCDebug(QQmlLSUtilsLog) << "Found following usages:";
- for (auto r : result) {
+ qCDebug(QQmlLSUtilsLog) << "Found following usages in files:";
+ for (auto r : result.usagesInFile()) {
qCDebug(QQmlLSUtilsLog)
<< r.filename << " @ " << r.sourceLocation.startLine << ":"
<< r.sourceLocation.startColumn << " with length " << r.sourceLocation.length;
}
+ qCDebug(QQmlLSUtilsLog) << "And following usages in file names:"
+ << result.usagesInFilename();
}
return result;
}
-static std::optional<QQmlLSUtilsIdentifierType>
-hasMethodOrSignal(const QQmlJSScope::ConstPtr &scope, const QString &name)
+static std::optional<IdentifierType> hasMethodOrSignal(const QQmlJSScope::ConstPtr &scope,
+ const QString &name)
{
auto methods = scope->methods(name);
if (methods.isEmpty())
return {};
const bool isSignal = methods.front().methodType() == QQmlJSMetaMethodType::Signal;
- QQmlLSUtilsIdentifierType type = isSignal ? QQmlLSUtilsIdentifierType::SignalIdentifier
- : QQmlLSUtilsIdentifierType::MethodIdentifier;
+ IdentifierType type =
+ isSignal ? IdentifierType::SignalIdentifier : IdentifierType::MethodIdentifier;
return type;
}
@@ -1059,24 +1058,22 @@ linting module already warns about calling methods from parent scopes.
Note: in QML, one can only call methods from the current scope, and from the QML file root scope.
Everything else needs a qualifier.
*/
-static std::optional<QQmlLSUtilsExpressionType>
+static std::optional<ExpressionType>
methodFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QString &name,
- QQmlLSUtilsResolveOptions options)
+ ResolveOptions options)
{
for (QQmlJSScope::ConstPtr current = referrerScope; current; current = current->parentScope()) {
if (auto type = hasMethodOrSignal(current, name)) {
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{ name,
- findDefiningScopeForMethod(current, name),
- *type };
+ return ExpressionType{ name, findDefiningScopeForMethod(current, name), *type };
case ResolveActualTypeForFieldMemberExpression:
// QQmlJSScopes were not implemented for methods yet, but JS functions have methods
// and properties see
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
// for the list of properties/methods of functions. Therefore return a null scope.
// see also code below for non-qualified method access
- return QQmlLSUtilsExpressionType{ name, {}, *type };
+ return ExpressionType{ name, {}, *type };
}
}
@@ -1084,13 +1081,11 @@ methodFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QStrin
if (auto type = hasMethodOrSignal(current, *signalName)) {
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
- name, findDefiningScopeForMethod(current, *signalName),
- SignalHandlerIdentifier
- };
+ return ExpressionType{ name, findDefiningScopeForMethod(current, *signalName),
+ SignalHandlerIdentifier };
case ResolveActualTypeForFieldMemberExpression:
// Properties and methods of JS methods are not supported yet
- return QQmlLSUtilsExpressionType{ name, {}, SignalHandlerIdentifier };
+ return ExpressionType{ name, {}, SignalHandlerIdentifier };
}
}
}
@@ -1103,9 +1098,9 @@ methodFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QStrin
\internal
See comment on methodFromReferrerScope: the same applies to properties.
*/
-static std::optional<QQmlLSUtilsExpressionType>
+static std::optional<ExpressionType>
propertyFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QString &propertyName,
- QQmlLSUtilsResolveOptions options)
+ ResolveOptions options)
{
for (QQmlJSScope::ConstPtr current = referrerScope; current; current = current->parentScope()) {
const auto resolved = resolveNameInQmlScope(propertyName, current);
@@ -1115,13 +1110,11 @@ propertyFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QStr
if (auto property = current->property(resolved->name); property.isValid()) {
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
- propertyName, findDefiningScopeForProperty(current, propertyName),
- resolved->type
- };
+ return ExpressionType{ propertyName,
+ findDefiningScopeForProperty(current, propertyName),
+ resolved->type };
case ResolveActualTypeForFieldMemberExpression:
- return QQmlLSUtilsExpressionType{ propertyName, property.type(),
- resolved->type };
+ return ExpressionType{ propertyName, property.type(), resolved->type };
}
}
}
@@ -1135,23 +1128,20 @@ See comment on methodFromReferrerScope: the same applies to property bindings.
If resolver is not null then it is used to resolve the id with which a generalized grouped
properties starts.
*/
-static std::optional<QQmlLSUtilsExpressionType>
+static std::optional<ExpressionType>
propertyBindingFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QString &name,
- QQmlLSUtilsResolveOptions options,
- QQmlJSTypeResolver *resolverForIds)
+ ResolveOptions options, QQmlJSTypeResolver *resolverForIds)
{
- auto bindings = referrerScope->propertyBindings(name);
+ const auto bindings = referrerScope->propertyBindings(name);
if (bindings.isEmpty())
return {};
- const auto binding = bindings.front();
-
- if ((binding.bindingType() != QQmlSA::BindingType::AttachedProperty)
- && (binding.bindingType() != QQmlSA::BindingType::GroupProperty))
+ const auto binding = bindings.begin();
+ const auto bindingType = binding->bindingType();
+ const bool bindingIsAttached = bindingType == QQmlSA::BindingType::AttachedProperty;
+ if (!bindingIsAttached && bindingType != QQmlSA::BindingType::GroupProperty)
return {};
- const bool bindingIsAttached = binding.bindingType() == QQmlSA::BindingType::AttachedProperty;
-
// Generalized grouped properties, like Bindings or PropertyChanges, for example, have bindings
// starting in an id (like `someId.someProperty: ...`).
// If `someid` is not a property and is a deferred name, then it should be an id.
@@ -1164,34 +1154,34 @@ propertyBindingFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, con
referrerScope, name, QQmlJSRegisterContent::InvalidLookupIndex,
AssumeComponentsAreBound);
if (fromId.variant() == QQmlJSRegisterContent::ObjectById)
- return QQmlLSUtilsExpressionType{ name, fromId.type(), QmlObjectIdIdentifier };
+ return ExpressionType{ name, fromId.type(), QmlObjectIdIdentifier };
- return QQmlLSUtilsExpressionType{ name, {}, QmlObjectIdIdentifier };
+ return ExpressionType{ name, {}, QmlObjectIdIdentifier };
}
const auto typeIdentifier =
bindingIsAttached ? AttachedTypeIdentifier : GroupedPropertyIdentifier;
- const auto getScope = [&bindingIsAttached, &binding]() -> QQmlJSScope::ConstPtr {
+ const auto getScope = [bindingIsAttached, binding]() -> QQmlJSScope::ConstPtr {
if (bindingIsAttached)
- return binding.attachingType();
+ return binding->attachingType();
- return binding.groupType();
+ return binding->groupType();
};
switch (options) {
case ResolveOwnerType: {
- return QQmlLSUtilsExpressionType{
- name,
- // note: always return the type of the attached type as the owner.
- // Find usages on "Keys.", for example, should yield all usages of the "Keys"
- // attached property.
- bindingIsAttached ? getScope() : findDefiningScopeForProperty(referrerScope, name),
- typeIdentifier
- };
+ return ExpressionType{ name,
+ // note: always return the type of the attached type as the owner.
+ // Find usages on "Keys.", for example, should yield all usages of
+ // the "Keys" attached property.
+ bindingIsAttached
+ ? getScope()
+ : findDefiningScopeForProperty(referrerScope, name),
+ typeIdentifier };
}
case ResolveActualTypeForFieldMemberExpression:
- return QQmlLSUtilsExpressionType{ name, getScope(), typeIdentifier };
+ return ExpressionType{ name, getScope(), typeIdentifier };
}
Q_UNREACHABLE_RETURN({});
}
@@ -1200,7 +1190,8 @@ propertyBindingFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, con
Finds the scope within the special elements like Connections,
PropertyChanges, Bindings or AnchorChanges.
*/
-static QQmlJSScope::ConstPtr findScopeOfSpecialItems(QQmlJSScope::ConstPtr scope, const DomItem &item)
+static QQmlJSScope::ConstPtr findScopeOfSpecialItems(
+ const QQmlJSScope::ConstPtr &scope, const DomItem &item)
{
if (!scope)
return {};
@@ -1211,7 +1202,7 @@ static QQmlJSScope::ConstPtr findScopeOfSpecialItems(QQmlJSScope::ConstPtr scope
u"QQuickAnchorChanges"_s};
const auto special = QQmlJSUtils::searchBaseAndExtensionTypes(
- scope, [&specialItems](QQmlJSScope::ConstPtr visitedScope) {
+ scope, [&specialItems](const QQmlJSScope::ConstPtr &visitedScope) {
const auto typeName = visitedScope->internalName();
if (specialItems.contains(typeName))
return true;
@@ -1259,14 +1250,13 @@ static QQmlJSScope::ConstPtr findScopeOfSpecialItems(QQmlJSScope::ConstPtr scope
return {};
}
-static std::optional<QQmlLSUtilsExpressionType>
-resolveFieldMemberExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions options)
+static std::optional<ExpressionType> resolveFieldMemberExpressionType(const DomItem &item,
+ ResolveOptions options)
{
const QString name = item.field(Fields::identifier).value().toString();
DomItem parent = item.directParent();
- auto owner = QQmlLSUtils::resolveExpressionType(
- parent.field(Fields::left),
- QQmlLSUtilsResolveOptions::ResolveActualTypeForFieldMemberExpression);
+ auto owner = resolveExpressionType(parent.field(Fields::left),
+ ResolveOptions::ResolveActualTypeForFieldMemberExpression);
if (!owner)
return {};
@@ -1289,11 +1279,11 @@ resolveFieldMemberExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions
.rootQmlObject(GoTo::MostLikely)
.semanticScope();
if (scope->hasEnumerationKey(name)) {
- return QQmlLSUtilsExpressionType{name, scope, EnumeratorValueIdentifier};
+ return ExpressionType{ name, scope, EnumeratorValueIdentifier };
}
// Or it is a enum name <TypeName>.<EnumName>.<EnumValue>
else if (scope->hasEnumeration(name)) {
- return QQmlLSUtilsExpressionType{name, scope, EnumeratorIdentifier};
+ return ExpressionType{ name, scope, EnumeratorIdentifier };
}
// check inline components <TypeName>.<InlineComponentName>
@@ -1301,7 +1291,7 @@ resolveFieldMemberExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions
end = owner->semanticScope->childScopesEnd();
it != end; ++it) {
if ((*it)->inlineComponentName() == name) {
- return QQmlLSUtilsExpressionType{ name, *it, QmlComponentIdentifier };
+ return ExpressionType{ name, *it, QmlComponentIdentifier };
}
}
return {};
@@ -1311,30 +1301,28 @@ resolveFieldMemberExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions
return owner;
}
-static std::optional<QQmlLSUtilsExpressionType>
-resolveIdentifierExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions options)
+static std::optional<ExpressionType> resolveIdentifierExpressionType(const DomItem &item,
+ ResolveOptions options)
{
- if (QQmlLSUtils::isFieldMemberAccess(item)) {
+ if (isFieldMemberAccess(item)) {
return resolveFieldMemberExpressionType(item, options);
}
const QString name = item.field(Fields::identifier).value().toString();
- if (DomItem definitionOfItem = findJSIdentifierDefinition(item, name)) {
+ if (const DomItem definitionOfItem = findJSIdentifierDefinition(item, name)) {
Q_ASSERT_X(!definitionOfItem.semanticScope().isNull()
&& definitionOfItem.semanticScope()->ownJSIdentifier(name),
"QQmlLSUtils::findDefinitionOf",
"JS definition does not actually define the JS identifer. "
"It should be empty.");
- auto scope = definitionOfItem.semanticScope();
- auto jsIdentifier = scope->ownJSIdentifier(name);
- if (jsIdentifier->scope) {
- return QQmlLSUtilsExpressionType{ name, jsIdentifier->scope.toStrongRef(),
- QQmlLSUtilsIdentifierType::JavaScriptIdentifier };
- } else {
- return QQmlLSUtilsExpressionType{ name, scope,
- QQmlLSUtilsIdentifierType::JavaScriptIdentifier };
- }
+ const auto scope = definitionOfItem.semanticScope();
+ const auto jsIdentifier = scope->ownJSIdentifier(name);
+ return ExpressionType {
+ name,
+ jsIdentifier->scope ? QQmlJSScope::ConstPtr(jsIdentifier->scope.toStrongRef()) : scope,
+ IdentifierType::JavaScriptIdentifier
+ };
}
const auto referrerScope = item.nearestSemanticScope();
@@ -1350,53 +1338,51 @@ resolveIdentifierExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions o
return {};
// check if its found as a property binding
- if (auto scope = propertyBindingFromReferrerScope(referrerScope, name, options, resolver.get()))
+ if (const auto scope = propertyBindingFromReferrerScope(
+ referrerScope, name, options, resolver.get())) {
return *scope;
+ }
// check if its an (unqualified) property
- if (auto scope = propertyFromReferrerScope(referrerScope, name, options))
+ if (const auto scope = propertyFromReferrerScope(referrerScope, name, options))
return *scope;
// Returns the baseType, can't use it with options.
- if (auto scope = resolver->typeForName(name)) {
+ if (const auto scope = resolver->typeForName(name)) {
if (scope->isSingleton())
- return QQmlLSUtilsExpressionType{ name, scope,
- QQmlLSUtilsIdentifierType::SingletonIdentifier };
+ return ExpressionType{ name, scope, IdentifierType::SingletonIdentifier };
- if (auto attachedScope = scope->attachedType()) {
- return QQmlLSUtilsExpressionType{
- name, attachedScope, QQmlLSUtilsIdentifierType::AttachedTypeIdentifier
- };
- }
+ if (const auto attachedScope = scope->attachedType())
+ return ExpressionType{ name, attachedScope, IdentifierType::AttachedTypeIdentifier };
// its a (inline) component!
- return QQmlLSUtilsExpressionType{ name, scope, QmlComponentIdentifier };
+ return ExpressionType{ name, scope, QmlComponentIdentifier };
}
// check if its an id
- QQmlJSRegisterContent fromId =
+ const QQmlJSRegisterContent fromId =
resolver->scopedType(referrerScope, name, QQmlJSRegisterContent::InvalidLookupIndex,
AssumeComponentsAreBound);
if (fromId.variant() == QQmlJSRegisterContent::ObjectById)
- return QQmlLSUtilsExpressionType{ name, fromId.type(), QmlObjectIdIdentifier };
+ return ExpressionType{ name, fromId.type(), QmlObjectIdIdentifier };
const QQmlJSScope::ConstPtr jsGlobal = resolver->jsGlobalObject();
// check if its a JS global method
- if (auto scope = methodFromReferrerScope(jsGlobal, name, options))
+ if (const auto scope = methodFromReferrerScope(jsGlobal, name, options))
return scope;
// check if its an JS global property
- if (auto scope = propertyFromReferrerScope(jsGlobal, name, options))
+ if (const auto scope = propertyFromReferrerScope(jsGlobal, name, options))
return *scope;
return {};
}
-static std::optional<QQmlLSUtilsExpressionType>
+static std::optional<ExpressionType>
resolveSignalOrPropertyExpressionType(const QString &name, const QQmlJSScope::ConstPtr &scope,
- QQmlLSUtilsResolveOptions options)
+ ResolveOptions options)
{
- auto signalOrProperty = resolveNameInQmlScope(name, scope);
+ const auto signalOrProperty = resolveNameInQmlScope(name, scope);
if (!signalOrProperty)
return {};
@@ -1404,20 +1390,18 @@ resolveSignalOrPropertyExpressionType(const QString &name, const QQmlJSScope::Co
case PropertyIdentifier:
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{ name, findDefiningScopeForProperty(scope, name),
- signalOrProperty->type };
+ return ExpressionType{ name, findDefiningScopeForProperty(scope, name),
+ signalOrProperty->type };
case ResolveActualTypeForFieldMemberExpression:
- return QQmlLSUtilsExpressionType{ name, scope->property(name).type(),
- signalOrProperty->type };
+ return ExpressionType{ name, scope->property(name).type(), signalOrProperty->type };
}
Q_UNREACHABLE_RETURN({});
case PropertyChangedHandlerIdentifier:
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
- name, findDefiningScopeForProperty(scope, signalOrProperty->name),
- signalOrProperty->type
- };
+ return ExpressionType{ name,
+ findDefiningScopeForProperty(scope, signalOrProperty->name),
+ signalOrProperty->type };
case ResolveActualTypeForFieldMemberExpression:
// Properties and methods are not implemented on methods.
Q_UNREACHABLE_RETURN({});
@@ -1429,8 +1413,8 @@ resolveSignalOrPropertyExpressionType(const QString &name, const QQmlJSScope::Co
case MethodIdentifier:
switch (options) {
case ResolveOwnerType: {
- return QQmlLSUtilsExpressionType{ name, findDefiningScopeForMethod(scope, name),
- signalOrProperty->type };
+ return ExpressionType{ name, findDefiningScopeForMethod(scope, name),
+ signalOrProperty->type };
}
case ResolveActualTypeForFieldMemberExpression:
// Properties and methods are not implemented on methods.
@@ -1447,9 +1431,8 @@ resolveSignalOrPropertyExpressionType(const QString &name, const QQmlJSScope::Co
Resolves the type of the given DomItem, when possible (e.g., when there are enough type
annotations).
*/
-std::optional<QQmlLSUtilsExpressionType>
-QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
- QQmlLSUtilsResolveOptions options)
+std::optional<ExpressionType> resolveExpressionType(const QQmlJS::Dom::DomItem &item,
+ ResolveOptions options)
{
switch (item.internalKind()) {
case DomType::ScriptIdentifierExpression: {
@@ -1461,8 +1444,7 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
const auto &scope = propertyDefinition->semanticScope();
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{ propertyDefinition->name, scope,
- PropertyIdentifier };
+ return ExpressionType{ propertyDefinition->name, scope, PropertyIdentifier };
case ResolveActualTypeForFieldMemberExpression:
// There should not be any PropertyDefinition inside a FieldMemberExpression.
Q_UNREACHABLE_RETURN({});
@@ -1480,15 +1462,16 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
const QString name = binding->name();
if (name == u"id")
- return QQmlLSUtilsExpressionType{ name, owner.value(), QmlObjectIdIdentifier };
+ return ExpressionType{ name, owner.value(), QmlObjectIdIdentifier };
- if (QQmlJSScope::ConstPtr targetScope = findScopeOfSpecialItems(owner.value(), item)) {
+ if (const QQmlJSScope::ConstPtr targetScope
+ = findScopeOfSpecialItems(owner.value(), item)) {
const auto signalOrProperty = resolveNameInQmlScope(name, targetScope);
if (!signalOrProperty)
return {};
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
+ return ExpressionType{
name, findDefiningScopeForBinding(targetScope, signalOrProperty->name),
signalOrProperty->type
};
@@ -1515,13 +1498,13 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
const bool isComponent = name.front().isUpper();
if (isComponent)
scope = scope->baseType();
- const QQmlLSUtilsIdentifierType type =
+ const IdentifierType type =
isComponent ? QmlComponentIdentifier : GroupedPropertyIdentifier;
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{ name, scope, type };
+ return ExpressionType{ name, scope, type };
case ResolveActualTypeForFieldMemberExpression:
- return QQmlLSUtilsExpressionType{ name, scope, type};
+ return ExpressionType{ name, scope, type };
}
}
return {};
@@ -1539,20 +1522,20 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
name = name.sliced(dotIndex + 1);
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{ name, scope, QmlComponentIdentifier };
+ return ExpressionType{ name, scope, QmlComponentIdentifier };
case ResolveActualTypeForFieldMemberExpression:
- return QQmlLSUtilsExpressionType{ name, scope, QmlComponentIdentifier };
+ return ExpressionType{ name, scope, QmlComponentIdentifier };
}
Q_UNREACHABLE_RETURN({});
}
case DomType::MethodInfo: {
- auto object = item.as<MethodInfo>();
+ const auto object = item.as<MethodInfo>();
if (object && object->semanticScope()) {
std::optional<QQmlJSScope::ConstPtr> scope = object->semanticScope();
if (!scope)
return {};
- if (QQmlJSScope::ConstPtr targetScope =
+ if (const QQmlJSScope::ConstPtr targetScope =
findScopeOfSpecialItems(scope.value()->parentScope(), item)) {
const auto signalOrProperty = resolveNameInQmlScope(object->name, targetScope);
if (!signalOrProperty)
@@ -1560,10 +1543,10 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{ object->name,
- findDefiningScopeForMethod(
- targetScope, signalOrProperty->name),
- signalOrProperty->type };
+ return ExpressionType{ object->name,
+ findDefiningScopeForMethod(targetScope,
+ signalOrProperty->name),
+ signalOrProperty->type };
case ResolveActualTypeForFieldMemberExpression:
// not supported for methods
return {};
@@ -1575,8 +1558,8 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
if (scope.value()->scopeType() == QQmlJSScope::ScopeType::JSFunctionScope)
scope = scope.value()->parentScope();
- if (auto result = resolveSignalOrPropertyExpressionType(object->name, scope.value(),
- options)) {
+ if (const auto result = resolveSignalOrPropertyExpressionType(
+ object->name, scope.value(), options)) {
return result;
}
qDebug(QQmlLSUtilsLog) << "QQmlLSUtils::resolveExpressionType() could not resolve the"
@@ -1597,13 +1580,13 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
*/
const auto scope = item.qmlObject().semanticScope();
const auto name = item.field(Fields::value).value().toString();
- if (QQmlJSScope::ConstPtr targetScope = findScopeOfSpecialItems(scope, item)) {
+ if (const QQmlJSScope::ConstPtr targetScope = findScopeOfSpecialItems(scope, item)) {
const auto signalOrProperty = resolveNameInQmlScope(name, targetScope);
if (!signalOrProperty)
return {};
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
+ return ExpressionType{
name, findDefiningScopeForProperty(targetScope, signalOrProperty->name),
signalOrProperty->type
};
@@ -1617,32 +1600,36 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
}
case DomType::EnumItem: {
const QString enumValue = item.field(Fields::name).value().toString();
- QQmlJSScope::ConstPtr referrerScope = item.rootQmlObject(GoTo::MostLikely).semanticScope();
- if (!referrerScope->hasEnumerationKey(enumValue))
- return {};
- switch (options) {
- // special case: use the owner's scope here, as enums do not have their own
- // QQmlJSScope.
- case ResolveActualTypeForFieldMemberExpression:
- case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
- enumValue, findDefiningScopeForEnumerationKey(referrerScope, enumValue),
- EnumeratorValueIdentifier
- };
+ const QQmlJSScope::ConstPtr referrerScope
+ = item.rootQmlObject(GoTo::MostLikely).semanticScope();
+ if (!referrerScope->hasEnumerationKey(enumValue))
+ return {};
+ switch (options) {
+ // special case: use the owner's scope here, as enums do not have their own
+ // QQmlJSScope.
+ case ResolveActualTypeForFieldMemberExpression:
+ case ResolveOwnerType:
+ return ExpressionType {
+ enumValue,
+ findDefiningScopeForEnumerationKey(referrerScope, enumValue),
+ EnumeratorValueIdentifier
+ };
}
Q_UNREACHABLE_RETURN({});
}
case DomType::EnumDecl: {
const QString enumName = item.field(Fields::name).value().toString();
- QQmlJSScope::ConstPtr referrerScope = item.rootQmlObject(GoTo::MostLikely).semanticScope();
+ const QQmlJSScope::ConstPtr referrerScope
+ = item.rootQmlObject(GoTo::MostLikely).semanticScope();
if (!referrerScope->hasEnumeration(enumName))
return {};
switch (options) {
// special case: use the owner's scope here, as enums do not have their own QQmlJSScope.
case ResolveActualTypeForFieldMemberExpression:
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
- enumName, findDefiningScopeForEnumeration(referrerScope, enumName),
+ return ExpressionType {
+ enumName,
+ findDefiningScopeForEnumeration(referrerScope, enumName),
EnumeratorIdentifier
};
}
@@ -1658,8 +1645,7 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
Q_UNREACHABLE();
}
-DomItem QQmlLSUtils::sourceLocationToDomItem(const DomItem &file,
- const QQmlJS::SourceLocation &location)
+DomItem sourceLocationToDomItem(const DomItem &file, const QQmlJS::SourceLocation &location)
{
// QQmlJS::SourceLocation starts counting at 1 but the utils and the LSP start at 0.
auto items = QQmlLSUtils::itemsFromTextLocation(file, location.startLine - 1,
@@ -1694,7 +1680,7 @@ DomItem QQmlLSUtils::sourceLocationToDomItem(const DomItem &file,
return {};
}
-static std::optional<QQmlLSUtilsLocation>
+static std::optional<Location>
findMethodDefinitionOf(const DomItem &file, QQmlJS::SourceLocation location, const QString &name)
{
DomItem owner = QQmlLSUtils::sourceLocationToDomItem(file, location).qmlObject();
@@ -1706,7 +1692,7 @@ findMethodDefinitionOf(const DomItem &file, QQmlJS::SourceLocation location, con
auto regions = fileLocation->info().regions;
if (auto it = regions.constFind(IdentifierRegion); it != regions.constEnd()) {
- QQmlLSUtilsLocation result;
+ Location result;
result.sourceLocation = *it;
result.filename = method.canonicalFilePath();
return result;
@@ -1715,7 +1701,7 @@ findMethodDefinitionOf(const DomItem &file, QQmlJS::SourceLocation location, con
return {};
}
-static std::optional<QQmlLSUtilsLocation>
+static std::optional<Location>
findPropertyDefinitionOf(const DomItem &file, QQmlJS::SourceLocation propertyDefinitionLocation,
const QString &name)
{
@@ -1729,7 +1715,7 @@ findPropertyDefinitionOf(const DomItem &file, QQmlJS::SourceLocation propertyDef
auto regions = fileLocation->info().regions;
if (auto it = regions.constFind(IdentifierRegion); it != regions.constEnd()) {
- QQmlLSUtilsLocation result;
+ Location result;
result.sourceLocation = *it;
result.filename = propertyDefinition.canonicalFilePath();
return result;
@@ -1738,10 +1724,9 @@ findPropertyDefinitionOf(const DomItem &file, QQmlJS::SourceLocation propertyDef
return {};
}
-std::optional<QQmlLSUtilsLocation> QQmlLSUtils::findDefinitionOf(const DomItem &item)
+std::optional<Location> findDefinitionOf(const DomItem &item)
{
- auto resolvedExpression =
- resolveExpressionType(item, QQmlLSUtilsResolveOptions::ResolveOwnerType);
+ auto resolvedExpression = resolveExpressionType(item, ResolveOptions::ResolveOwnerType);
if (!resolvedExpression || !resolvedExpression->name || !resolvedExpression->semanticScope) {
qCDebug(QQmlLSUtilsLog) << "QQmlLSUtils::findDefinitionOf: Type could not be resolved.";
@@ -1755,7 +1740,7 @@ std::optional<QQmlLSUtilsLocation> QQmlLSUtils::findDefinitionOf(const DomItem &
.value()
.location;
- return QQmlLSUtilsLocation{ resolvedExpression->semanticScope->filePath(), location };
+ return Location{ resolvedExpression->semanticScope->filePath(), location };
}
case PropertyIdentifier: {
@@ -1789,13 +1774,13 @@ std::optional<QQmlLSUtilsLocation> QQmlLSUtils::findDefinitionOf(const DomItem &
return {};
}
- QQmlLSUtilsLocation result;
+ Location result;
result.sourceLocation = FileLocations::treeOf(domId)->info().fullRegion;
result.filename = domId.canonicalFilePath();
return result;
}
case QmlComponentIdentifier: {
- QQmlLSUtilsLocation result;
+ Location result;
result.sourceLocation = resolvedExpression->semanticScope->sourceLocation();
result.filename = resolvedExpression->semanticScope->filePath();
return result;
@@ -1850,8 +1835,7 @@ static QQmlJSScope::ConstPtr methodOwnerFrom(const QQmlJSScope::ConstPtr &type,
return typeWithDefinition;
}
-static QQmlJSScope::ConstPtr
-expressionTypeWithDefinition(const QQmlLSUtilsExpressionType &ownerType)
+static QQmlJSScope::ConstPtr expressionTypeWithDefinition(const ExpressionType &ownerType)
{
switch (ownerType.type) {
case PropertyIdentifier:
@@ -1886,53 +1870,48 @@ expressionTypeWithDefinition(const QQmlLSUtilsExpressionType &ownerType)
return {};
}
-std::optional<QQmlLSUtilsErrorMessage> QQmlLSUtils::checkNameForRename(
- const DomItem &item, const QString &dirtyNewName,
- const std::optional<QQmlLSUtilsExpressionType> &ownerType)
+std::optional<ErrorMessage> checkNameForRename(const DomItem &item, const QString &dirtyNewName,
+ const std::optional<ExpressionType> &ownerType)
{
if (!ownerType) {
- if (const auto resolved = QQmlLSUtils::resolveExpressionType(item, ResolveOwnerType))
+ if (const auto resolved = resolveExpressionType(item, ResolveOwnerType))
return checkNameForRename(item, dirtyNewName, resolved);
}
// general checks for ECMAscript identifiers
if (!isValidEcmaScriptIdentifier(dirtyNewName))
- return QQmlLSUtilsErrorMessage{ 0, u"Invalid EcmaScript identifier!"_s };
+ return ErrorMessage{ 0, u"Invalid EcmaScript identifier!"_s };
const auto userSemanticScope = item.nearestSemanticScope();
if (!ownerType || !userSemanticScope) {
- return QQmlLSUtilsErrorMessage{ 0, u"Requested item cannot be renamed"_s };
+ return ErrorMessage{ 0, u"Requested item cannot be renamed"_s };
}
// type specific checks
switch (ownerType->type) {
case PropertyChangedSignalIdentifier: {
if (!QQmlSignalNames::isChangedSignalName(dirtyNewName)) {
- return QQmlLSUtilsErrorMessage{ 0, u"Invalid name for a property changed signal."_s };
+ return ErrorMessage{ 0, u"Invalid name for a property changed signal."_s };
}
break;
}
case PropertyChangedHandlerIdentifier: {
if (!QQmlSignalNames::isChangedHandlerName(dirtyNewName)) {
- return QQmlLSUtilsErrorMessage{
- 0, u"Invalid name for a property changed handler identifier."_s
- };
+ return ErrorMessage{ 0, u"Invalid name for a property changed handler identifier."_s };
}
break;
}
case SignalHandlerIdentifier: {
if (!QQmlSignalNames::isHandlerName(dirtyNewName)) {
- return QQmlLSUtilsErrorMessage{ 0, u"Invalid name for a signal handler identifier."_s };
+ return ErrorMessage{ 0, u"Invalid name for a signal handler identifier."_s };
}
break;
}
// TODO: any other specificities?
case QmlObjectIdIdentifier:
if (dirtyNewName.front().isLetter() && !dirtyNewName.front().isLower()) {
- return QQmlLSUtilsErrorMessage{
- 0, u"Object id names cannot start with an upper case letter."_s
- };
+ return ErrorMessage{ 0, u"Object id names cannot start with an upper case letter."_s };
}
break;
case JavaScriptIdentifier:
@@ -1946,7 +1925,7 @@ std::optional<QQmlLSUtilsErrorMessage> QQmlLSUtils::checkNameForRename(
auto typeWithDefinition = expressionTypeWithDefinition(*ownerType);
if (!typeWithDefinition) {
- return QQmlLSUtilsErrorMessage{
+ return ErrorMessage{
0,
u"Renaming has not been implemented for the requested item."_s,
};
@@ -1954,16 +1933,16 @@ std::optional<QQmlLSUtilsErrorMessage> QQmlLSUtils::checkNameForRename(
// is it not defined in QML?
if (!typeWithDefinition->isComposite()) {
- return QQmlLSUtilsErrorMessage{ 0, u"Cannot rename items defined in non-QML files."_s };
+ return ErrorMessage{ 0, u"Cannot rename items defined in non-QML files."_s };
}
// is it defined in the current module?
const QString moduleOfDefinition = ownerType->semanticScope->moduleName();
const QString moduleOfCurrentItem = userSemanticScope->moduleName();
if (moduleOfDefinition != moduleOfCurrentItem) {
- return QQmlLSUtilsErrorMessage{
+ return ErrorMessage{
0,
- u"Cannot rename items defined in the %1 module fromits usage in the %2 module."_s
+ u"Cannot rename items defined in the \"%1\" module from a usage in the \"%2\" module."_s
.arg(moduleOfDefinition, moduleOfCurrentItem),
};
}
@@ -1993,8 +1972,7 @@ static std::optional<QString> oldNameFrom(const DomItem &item)
Q_UNREACHABLE_RETURN(std::nullopt);
}
-static std::optional<QString> newNameFrom(const QString &dirtyNewName,
- QQmlLSUtilsIdentifierType alternative)
+static std::optional<QString> newNameFrom(const QString &dirtyNewName, IdentifierType alternative)
{
// When renaming signal/property changed handlers and property changed signals:
// Get the actual corresponding signal name (for signal handlers) or property name (for
@@ -2035,27 +2013,26 @@ Special cases:
All of the chopping operations are done using the static helpers from QQmlSignalNames.
\endlist
*/
-QList<QQmlLSUtilsEdit> QQmlLSUtils::renameUsagesOf(
- const DomItem &item, const QString &dirtyNewName,
- const std::optional<QQmlLSUtilsExpressionType> &targetType)
+RenameUsages renameUsagesOf(const DomItem &item, const QString &dirtyNewName,
+ const std::optional<ExpressionType> &targetType)
{
- QList<QQmlLSUtilsEdit> results;
- const QList<QQmlLSUtilsLocation> locations = findUsagesOf(item);
+ RenameUsages result;
+ const Usages locations = findUsagesOf(item);
if (locations.isEmpty())
- return results;
+ return result;
auto oldName = oldNameFrom(item);
if (!oldName)
- return results;
+ return result;
QQmlJSScope::ConstPtr semanticScope;
if (targetType) {
semanticScope = targetType->semanticScope;
- } else if (const auto resolved = QQmlLSUtils::resolveExpressionType(
- item, QQmlLSUtilsResolveOptions::ResolveOwnerType)) {
+ } else if (const auto resolved =
+ QQmlLSUtils::resolveExpressionType(item, ResolveOptions::ResolveOwnerType)) {
semanticScope = resolved->semanticScope;
} else {
- return results;
+ return result;
}
QString newName;
@@ -2080,9 +2057,9 @@ QList<QQmlLSUtilsEdit> QQmlLSUtils::renameUsagesOf(
QQmlSignalNames::propertyNameToChangedHandlerName(newName);
// set the new name at the found usages, but add "on"-prefix and "Changed"-suffix if needed
- for (const auto &location : locations) {
+ for (const auto &location : locations.usagesInFile()) {
const qsizetype currentLength = location.sourceLocation.length;
- QQmlLSUtilsEdit edit;
+ Edit edit;
edit.location = location;
if (oldNameLength == currentLength) {
// normal case, nothing to do
@@ -2104,35 +2081,52 @@ QList<QQmlLSUtilsEdit> QQmlLSUtils::renameUsagesOf(
qCDebug(QQmlLSUtilsLog) << "Found usage with wrong identifier length, ignoring...";
continue;
}
- results.append(edit);
+ result.appendRename(edit);
}
- return results;
+ for (const auto &filename : locations.usagesInFilename()) {
+ // assumption: we only rename files ending in .qml or .ui.qml in qmlls
+ QString extension;
+ if (filename.endsWith(u".ui.qml"_s))
+ extension = u".ui.qml"_s;
+ else if (filename.endsWith(u".qml"_s))
+ extension = u".qml"_s;
+ else
+ continue;
+
+ QFileInfo info(filename);
+ // do not rename the file if it has a custom type name in the qmldir
+ if (!info.isFile() || info.baseName() != oldName)
+ continue;
+
+ const QString newFilename =
+ QDir::cleanPath(filename + "/..").append(u"/"_s).append(newName).append(extension);
+ result.appendRename({ filename, newFilename });
+ }
+
+ return result;
}
-QQmlLSUtilsLocation QQmlLSUtilsLocation::from(const QString &fileName, const QString &code,
- quint32 startLine, quint32 startCharacter,
- quint32 length)
+Location Location::from(const QString &fileName, const QString &code, quint32 startLine,
+ quint32 startCharacter, quint32 length)
{
quint32 offset = QQmlLSUtils::textOffsetFrom(code, startLine - 1, startCharacter - 1);
- QQmlLSUtilsLocation location{
- fileName, QQmlJS::SourceLocation{ offset, length, startLine, startCharacter }
- };
+ Location location{ fileName,
+ QQmlJS::SourceLocation{ offset, length, startLine, startCharacter } };
return location;
}
-QQmlLSUtilsEdit QQmlLSUtilsEdit::from(const QString &fileName, const QString &code,
- quint32 startLine, quint32 startCharacter, quint32 length,
- const QString &newName)
+Edit Edit::from(const QString &fileName, const QString &code, quint32 startLine,
+ quint32 startCharacter, quint32 length, const QString &newName)
{
- QQmlLSUtilsEdit rename;
- rename.location = QQmlLSUtilsLocation::from(fileName, code, startLine, startCharacter, length);
+ Edit rename;
+ rename.location = Location::from(fileName, code, startLine, startCharacter, length);
rename.replacement = newName;
return rename;
}
-bool QQmlLSUtils::isValidEcmaScriptIdentifier(QStringView identifier)
+bool isValidEcmaScriptIdentifier(QStringView identifier)
{
QQmlJS::Lexer lexer(nullptr);
lexer.setCode(identifier.toString(), 0);
@@ -2158,7 +2152,7 @@ https://doc.qt.io/qt-6/windows-building.html#step-2-install-build-requirements c
to have CMake in your path to build Qt. So a developer machine running qmlls has a high chance of
having CMake in their path, if CMake is installed and used.
*/
-QPair<QString, QStringList> QQmlLSUtils::cmakeBuildCommand(const QString &path)
+QPair<QString, QStringList> cmakeBuildCommand(const QString &path)
{
const QPair<QString, QStringList> result{
u"cmake"_s, { u"--build"_s, path, u"-t"_s, u"all_qmltyperegistrations"_s }
@@ -2166,18 +2160,32 @@ QPair<QString, QStringList> QQmlLSUtils::cmakeBuildCommand(const QString &path)
return result;
}
+void Usages::sort()
+{
+ std::sort(m_usagesInFile.begin(), m_usagesInFile.end());
+ std::sort(m_usagesInFilename.begin(), m_usagesInFilename.end());
+}
-QByteArray QQmlLSUtils::getDocumentationFromLocation(const DomItem &file, const QQmlLSUtilsTextPosition &position)
+bool Usages::isEmpty() const
{
- QByteArray result;
- const auto [line, character] = position;
- const auto itemLocation = itemsFromTextLocation(file, line, character);
+ return m_usagesInFilename.isEmpty() && m_usagesInFile.isEmpty();
+}
- // TODO:
- // Process found item's internalKind and fetch its documentation.
- Q_UNUSED(itemLocation);
+Usages::Usages(const QList<Location> &usageInFile, const QList<QString> &usageInFilename)
+ : m_usagesInFile(usageInFile), m_usagesInFilename(usageInFilename)
+{
+ std::sort(m_usagesInFile.begin(), m_usagesInFile.end());
+ std::sort(m_usagesInFilename.begin(), m_usagesInFilename.end());
+}
- return result;
+RenameUsages::RenameUsages(const QList<Edit> &renamesInFile,
+ const QList<FileRename> &renamesInFilename)
+ : m_renamesInFile(renamesInFile), m_renamesInFilename(renamesInFilename)
+{
+ std::sort(m_renamesInFile.begin(), m_renamesInFile.end());
+ std::sort(m_renamesInFilename.begin(), m_renamesInFilename.end());
}
+} // namespace QQmlLSUtils
+
QT_END_NAMESPACE
diff --git a/src/qmlls/qqmllsutils_p.h b/src/qmlls/qqmllsutils_p.h
index 0ba58f8294..22e55c66e8 100644
--- a/src/qmlls/qqmllsutils_p.h
+++ b/src/qmlls/qqmllsutils_p.h
@@ -27,19 +27,21 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QQmlLSUtilsLog);
-struct QQmlLSUtilsItemLocation
+namespace QQmlLSUtils {
+
+struct ItemLocation
{
QQmlJS::Dom::DomItem domItem;
QQmlJS::Dom::FileLocations::Tree fileLocation;
};
-struct QQmlLSUtilsTextPosition
+struct TextPosition
{
int line;
int character;
};
-enum QQmlLSUtilsIdentifierType : char {
+enum IdentifierType : char {
JavaScriptIdentifier,
PropertyIdentifier,
PropertyChangedSignalIdentifier,
@@ -56,53 +58,75 @@ enum QQmlLSUtilsIdentifierType : char {
QmlComponentIdentifier,
};
-struct QQmlLSUtilsErrorMessage
+struct ErrorMessage
{
int code;
QString message;
};
-struct QQmlLSUtilsExpressionType
+struct ExpressionType
{
std::optional<QString> name;
QQmlJSScope::ConstPtr semanticScope;
- QQmlLSUtilsIdentifierType type;
+ IdentifierType type;
};
-struct QQmlLSUtilsLocation
+struct Location
{
QString filename;
QQmlJS::SourceLocation sourceLocation;
- static QQmlLSUtilsLocation from(const QString &fileName, const QString &code, quint32 startLine,
- quint32 startCharacter, quint32 length);
+ static Location from(const QString &fileName, const QString &code, quint32 startLine,
+ quint32 startCharacter, quint32 length);
- friend bool operator<(const QQmlLSUtilsLocation &a, const QQmlLSUtilsLocation &b)
+ friend bool operator<(const Location &a, const Location &b)
{
return std::make_tuple(a.filename, a.sourceLocation.begin(), a.sourceLocation.end())
< std::make_tuple(b.filename, b.sourceLocation.begin(), b.sourceLocation.end());
}
- friend bool operator==(const QQmlLSUtilsLocation &a, const QQmlLSUtilsLocation &b)
+ friend bool operator==(const Location &a, const Location &b)
{
return std::make_tuple(a.filename, a.sourceLocation.begin(), a.sourceLocation.end())
== std::make_tuple(b.filename, b.sourceLocation.begin(), b.sourceLocation.end());
}
};
-struct QQmlLSUtilsEdit
+/*!
+Represents a rename operation where the file itself needs to be renamed.
+\internal
+*/
+struct FileRename
{
- QQmlLSUtilsLocation location;
+ QString oldFilename;
+ QString newFilename;
+
+ friend bool comparesEqual(const FileRename &a, const FileRename &b) noexcept
+ {
+ return std::tie(a.oldFilename, a.newFilename) == std::tie(b.oldFilename, b.newFilename);
+ }
+ friend Qt::strong_ordering compareThreeWay(const FileRename &a, const FileRename &b) noexcept
+ {
+ if (a.oldFilename != b.oldFilename)
+ return compareThreeWay(a.oldFilename, b.oldFilename);
+ return compareThreeWay(a.newFilename, b.newFilename);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(FileRename);
+};
+
+struct Edit
+{
+ Location location;
QString replacement;
- static QQmlLSUtilsEdit from(const QString &fileName, const QString &code, quint32 startLine,
- quint32 startCharacter, quint32 length, const QString &newName);
+ static Edit from(const QString &fileName, const QString &code, quint32 startLine,
+ quint32 startCharacter, quint32 length, const QString &newName);
- friend bool operator<(const QQmlLSUtilsEdit &a, const QQmlLSUtilsEdit &b)
+ friend bool operator<(const Edit &a, const Edit &b)
{
return std::make_tuple(a.location, a.replacement)
< std::make_tuple(b.location, b.replacement);
}
- friend bool operator==(const QQmlLSUtilsEdit &a, const QQmlLSUtilsEdit &b)
+ friend bool operator==(const Edit &a, const Edit &b)
{
return std::make_tuple(a.location, a.replacement)
== std::make_tuple(b.location, b.replacement);
@@ -110,6 +134,81 @@ struct QQmlLSUtilsEdit
};
/*!
+Represents the locations where some highlighting should take place, like in the "find all
+references" feature of the LSP. Those locations are pointing to parts of a Qml file or to a Qml
+file name.
+
+The file names are not reported as usage to the LSP and are currently only needed for the renaming
+operation to be able to rename files.
+
+\internal
+*/
+class Usages
+{
+public:
+ void sort();
+ bool isEmpty() const;
+
+ friend bool comparesEqual(const Usages &a, const Usages &b)
+ {
+ return a.m_usagesInFile == b.m_usagesInFile && a.m_usagesInFilename == b.m_usagesInFilename;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(Usages)
+
+ Usages() = default;
+ Usages(const QList<Location> &usageInFile, const QList<QString> &usageInFilename);
+
+ QList<Location> usagesInFile() const { return m_usagesInFile; };
+ QList<QString> usagesInFilename() const { return m_usagesInFilename; };
+
+ void appendUsage(const Location &edit)
+ {
+ if (!m_usagesInFile.contains(edit))
+ m_usagesInFile.append(edit);
+ };
+ void appendFilenameUsage(const QString &edit)
+ {
+
+ if (!m_usagesInFilename.contains(edit))
+ m_usagesInFilename.append(edit);
+ };
+
+private:
+ QList<Location> m_usagesInFile;
+ QList<QString> m_usagesInFilename;
+};
+
+/*!
+Represents the locations where a renaming should take place. Parts of text inside a file can be
+renamed and also filename themselves can be renamed.
+
+\internal
+*/
+class RenameUsages
+{
+public:
+ friend bool comparesEqual(const RenameUsages &a, const RenameUsages &b)
+ {
+ return std::tie(a.m_renamesInFile, a.m_renamesInFilename)
+ == std::tie(b.m_renamesInFile, b.m_renamesInFilename);
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(RenameUsages)
+
+ RenameUsages() = default;
+ RenameUsages(const QList<Edit> &renamesInFile, const QList<FileRename> &renamesInFilename);
+
+ QList<Edit> renameInFile() const { return m_renamesInFile; };
+ QList<FileRename> renameInFilename() const { return m_renamesInFilename; };
+
+ void appendRename(const Edit &edit) { m_renamesInFile.append(edit); };
+ void appendRename(const FileRename &edit) { m_renamesInFilename.append(edit); };
+
+private:
+ QList<Edit> m_renamesInFile;
+ QList<FileRename> m_renamesInFilename;
+};
+
+/*!
\internal
Choose whether to resolve the owner type or the entire type (the latter is only required to
resolve the types of qualified names and property accesses).
@@ -122,57 +221,54 @@ struct QQmlLSUtilsEdit
might lose some information about the owner. For example, resolving "x" in "myRectangle.x"
will return the JS type for float that was used to define the "x" property.
*/
-enum QQmlLSUtilsResolveOptions {
+enum ResolveOptions {
ResolveOwnerType,
ResolveActualTypeForFieldMemberExpression,
};
-enum class ImportCompletionType { None, Module, Version };
-
using DomItem = QQmlJS::Dom::DomItem;
-class QQmlLSUtils
-{
-public:
- static qsizetype textOffsetFrom(const QString &code, int row, int character);
- static QQmlLSUtilsTextPosition textRowAndColumnFrom(const QString &code, qsizetype offset);
- static QList<QQmlLSUtilsItemLocation> itemsFromTextLocation(const DomItem &file,
- int line, int character);
- static DomItem sourceLocationToDomItem(const DomItem &file,
- const QQmlJS::SourceLocation &location);
- static QByteArray lspUriToQmlUrl(const QByteArray &uri);
- static QByteArray qmlUrlToLspUri(const QByteArray &url);
- static QLspSpecification::Range qmlLocationToLspLocation(const QString &code,
- QQmlJS::SourceLocation qmlLocation);
- static DomItem baseObject(const DomItem &qmlObject);
- static std::optional<QQmlLSUtilsLocation>
- findTypeDefinitionOf(const DomItem &item);
- static std::optional<QQmlLSUtilsLocation> findDefinitionOf(const DomItem &item);
- static QList<QQmlLSUtilsLocation> findUsagesOf(const DomItem &item);
-
- static std::optional<QQmlLSUtilsErrorMessage> checkNameForRename(
- const DomItem &item, const QString &newName,
- const std::optional<QQmlLSUtilsExpressionType> &targetType = std::nullopt);
- static QList<QQmlLSUtilsEdit> renameUsagesOf(
- const DomItem &item, const QString &newName,
- const std::optional<QQmlLSUtilsExpressionType> &targetType = std::nullopt);
-
- static std::optional<QQmlLSUtilsExpressionType> resolveExpressionType(
- const DomItem &item, QQmlLSUtilsResolveOptions);
- static bool isValidEcmaScriptIdentifier(QStringView view);
-
- static QPair<QString, QStringList> cmakeBuildCommand(const QString &path);
-
- // Documentation Hints
- static QByteArray getDocumentationFromLocation(const DomItem &file, const QQmlLSUtilsTextPosition &position);
-
- static bool isFieldMemberExpression(const DomItem &item);
- static bool isFieldMemberAccess(const DomItem &item);
- static QStringList fieldMemberExpressionBits(const DomItem &item,
- const DomItem &stopAtChild = {});
-
- static QString qualifiersFrom(const DomItem &el);
-};
+qsizetype textOffsetFrom(const QString &code, int row, int character);
+TextPosition textRowAndColumnFrom(const QString &code, qsizetype offset);
+QList<ItemLocation> itemsFromTextLocation(const DomItem &file, int line, int character);
+DomItem sourceLocationToDomItem(const DomItem &file, const QQmlJS::SourceLocation &location);
+QByteArray lspUriToQmlUrl(const QByteArray &uri);
+QByteArray qmlUrlToLspUri(const QByteArray &url);
+QLspSpecification::Range qmlLocationToLspLocation(const QString &code,
+ QQmlJS::SourceLocation qmlLocation);
+DomItem baseObject(const DomItem &qmlObject);
+std::optional<Location> findTypeDefinitionOf(const DomItem &item);
+std::optional<Location> findDefinitionOf(const DomItem &item);
+Usages findUsagesOf(const DomItem &item);
+
+std::optional<ErrorMessage>
+checkNameForRename(const DomItem &item, const QString &newName,
+ const std::optional<ExpressionType> &targetType = std::nullopt);
+RenameUsages renameUsagesOf(const DomItem &item, const QString &newName,
+ const std::optional<ExpressionType> &targetType = std::nullopt);
+std::optional<ExpressionType> resolveExpressionType(const DomItem &item, ResolveOptions);
+bool isValidEcmaScriptIdentifier(QStringView view);
+
+QPair<QString, QStringList> cmakeBuildCommand(const QString &path);
+
+bool isFieldMemberExpression(const DomItem &item);
+bool isFieldMemberAccess(const DomItem &item);
+QStringList fieldMemberExpressionBits(const DomItem &item, const DomItem &stopAtChild = {});
+
+QString qualifiersFrom(const DomItem &el);
+
+QQmlJSScope::ConstPtr findDefiningScopeForProperty(QQmlJSScope::ConstPtr referrerScope,
+ const QString &nameToCheck);
+QQmlJSScope::ConstPtr findDefiningScopeForBinding(QQmlJSScope::ConstPtr referrerScope,
+ const QString &nameToCheck);
+QQmlJSScope::ConstPtr findDefiningScopeForMethod(QQmlJSScope::ConstPtr referrerScope,
+ const QString &nameToCheck);
+QQmlJSScope::ConstPtr findDefiningScopeForEnumeration(QQmlJSScope::ConstPtr referrerScope,
+ const QString &nameToCheck);
+QQmlJSScope::ConstPtr findDefiningScopeForEnumerationKey(QQmlJSScope::ConstPtr referrerScope,
+ const QString &nameToCheck);
+} // namespace QQmlLSUtils
+
QT_END_NAMESPACE
#endif // QLANGUAGESERVERUTILS_P_H
diff --git a/src/qmlls/qqmlrenamesymbolsupport.cpp b/src/qmlls/qqmlrenamesymbolsupport.cpp
index a812b5a25c..a1e16ad87b 100644
--- a/src/qmlls/qqmlrenamesymbolsupport.cpp
+++ b/src/qmlls/qqmlrenamesymbolsupport.cpp
@@ -39,13 +39,15 @@ void QQmlRenameSymbolSupport::process(QQmlRenameSymbolSupport::RequestPointerArg
if (guard.setErrorFrom(itemsFound))
return;
- QQmlLSUtilsItemLocation &front = std::get<QList<QQmlLSUtilsItemLocation>>(itemsFound).front();
+ QQmlLSUtils::ItemLocation &front =
+ std::get<QList<QQmlLSUtils::ItemLocation>>(itemsFound).front();
const QString newName = QString::fromUtf8(request->m_parameters.newName);
- auto expressionType = QQmlLSUtils::resolveExpressionType(front.domItem, ResolveOwnerType);
+ auto expressionType =
+ QQmlLSUtils::resolveExpressionType(front.domItem, QQmlLSUtils::ResolveOwnerType);
if (!expressionType) {
- guard.setError(QQmlLSUtilsErrorMessage{ 0, u"Cannot rename the requested object"_s });
+ guard.setError(QQmlLSUtils::ErrorMessage{ 0, u"Cannot rename the requested object"_s });
return;
}
@@ -64,7 +66,7 @@ void QQmlRenameSymbolSupport::process(QQmlRenameSymbolSupport::RequestPointerArg
QHash<QString, QString> codeCache;
- for (const auto &rename : renames) {
+ for (const auto &rename : renames.renameInFile()) {
QLspSpecification::TextEdit edit;
const QUrl uri = QUrl::fromLocalFile(rename.location.filename);
@@ -103,6 +105,15 @@ void QQmlRenameSymbolSupport::process(QQmlRenameSymbolSupport::RequestPointerArg
}
editsByFileForResult.append(editsForCurrentFile);
}
+
+ // if files need to be renamed, then do it after the text edits
+ for (const auto &rename : renames.renameInFilename()) {
+ QLspSpecification::RenameFile currentRenameFile;
+ currentRenameFile.kind = "rename";
+ currentRenameFile.oldUri = QUrl::fromLocalFile(rename.oldFilename).toEncoded();
+ currentRenameFile.newUri = QUrl::fromLocalFile(rename.newFilename).toEncoded();
+ editsByFileForResult.append(currentRenameFile);
+ }
}
QT_END_NAMESPACE
diff --git a/src/qmlls/qqmlsemantictokens.cpp b/src/qmlls/qqmlsemantictokens.cpp
new file mode 100644
index 0000000000..03a7168149
--- /dev/null
+++ b/src/qmlls/qqmlsemantictokens.cpp
@@ -0,0 +1,771 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <qqmlsemantictokens_p.h>
+
+#include <QtQmlLS/private/qqmllsutils_p.h>
+#include <QtQmlDom/private/qqmldomscriptelements_p.h>
+#include <QtQmlDom/private/qqmldomfieldfilter_p.h>
+
+#include <QtLanguageServer/private/qlanguageserverprotocol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(semanticTokens, "qt.languageserver.semanticTokens")
+
+using namespace QQmlJS::AST;
+using namespace QQmlJS::Dom;
+using namespace QLspSpecification;
+
+static int tokenTypeFromRegion(QQmlJS::Dom::FileLocationRegion region)
+{
+ switch (region) {
+ case AsTokenRegion:
+ case BreakKeywordRegion:
+ case DoKeywordRegion:
+ case CaseKeywordRegion:
+ case CatchKeywordRegion:
+ case ComponentKeywordRegion:
+ case ContinueKeywordRegion:
+ case ElseKeywordRegion:
+ case EnumKeywordRegion:
+ case ForKeywordRegion:
+ case FinallyKeywordRegion:
+ case FunctionKeywordRegion:
+ case ImportTokenRegion:
+ case OnTokenRegion:
+ case PragmaKeywordRegion:
+ case ReturnKeywordRegion:
+ case SignalKeywordRegion:
+ case ThrowKeywordRegion:
+ case TryKeywordRegion:
+ case WhileKeywordRegion:
+ case PropertyKeywordRegion:
+ case InOfTokenRegion:
+ case DefaultKeywordRegion:
+ case ReadonlyKeywordRegion:
+ case RequiredKeywordRegion:
+ case IfKeywordRegion:
+ case SwitchKeywordRegion:
+ return int(SemanticTokenTypes::Keyword);
+ case QuestionMarkTokenRegion:
+ case EllipsisTokenRegion:
+ case OperatorTokenRegion:
+ return int(SemanticTokenTypes::Operator);
+ case QQmlJS::Dom::TypeIdentifierRegion:
+ return int(SemanticTokenTypes::Type);
+ case PragmaValuesRegion:
+ case IdentifierRegion:
+ case IdNameRegion:
+ return int(SemanticTokenTypes::Variable);
+ case ImportUriRegion:
+ return int(SemanticTokenTypes::Namespace);
+ case IdTokenRegion:
+ case OnTargetRegion:
+ return int(SemanticTokenTypes::Property);
+ case VersionRegion:
+ case EnumValueRegion:
+ return int(SemanticTokenTypes::Number);
+ default:
+ return int(SemanticTokenTypes::Variable);
+ }
+ Q_UNREACHABLE_RETURN({});
+}
+
+static FieldFilter highlightingFilter()
+{
+ QMultiMap<QString, QString> fieldFilterAdd{};
+ QMultiMap<QString, QString> fieldFilterRemove{
+ { QString(), QString::fromUtf16(Fields::propertyInfos) },
+ { QString(), QString::fromUtf16(Fields::fileLocationsTree) },
+ { QString(), QString::fromUtf16(Fields::importScope) },
+ { QString(), QString::fromUtf16(Fields::defaultPropertyName) },
+ { QString(), QString::fromUtf16(Fields::get) },
+ };
+ return FieldFilter{ fieldFilterAdd, fieldFilterRemove };
+}
+
+HighlightingVisitor::HighlightingVisitor(Highlights &highlights,
+ const std::optional<HighlightsRange> &range)
+ : m_highlights(highlights), m_range(range)
+{
+}
+
+bool HighlightingVisitor::operator()(Path, const DomItem &item, bool)
+{
+ if (m_range.has_value()) {
+ const auto fLocs = FileLocations::treeOf(item);
+ if (!fLocs)
+ return true;
+ const auto regions = fLocs->info().regions;
+ if (!HighlightingUtils::rangeOverlapsWithSourceLocation(regions[MainRegion],
+ m_range.value()))
+ return true;
+ }
+ switch (item.internalKind()) {
+ case DomType::Comment: {
+ highlightComment(item);
+ return true;
+ }
+ case DomType::Import: {
+ highlightImport(item);
+ return true;
+ }
+ case DomType::Binding: {
+ highlightBinding(item);
+ return true;
+ }
+ case DomType::Pragma: {
+ highlightPragma(item);
+ return true;
+ }
+ case DomType::EnumDecl: {
+ highlightEnumDecl(item);
+ return true;
+ }
+ case DomType::EnumItem: {
+ highlightEnumItem(item);
+ return true;
+ }
+ case DomType::QmlObject: {
+ highlightQmlObject(item);
+ return true;
+ }
+ case DomType::QmlComponent: {
+ highlightComponent(item);
+ return true;
+ }
+ case DomType::PropertyDefinition: {
+ highlightPropertyDefinition(item);
+ return true;
+ }
+ case DomType::MethodInfo: {
+ highlightMethod(item);
+ return true;
+ }
+ case DomType::ScriptLiteral: {
+ highlightScriptLiteral(item);
+ return true;
+ }
+ case DomType::ScriptIdentifierExpression: {
+ highlightIdentifier(item);
+ return true;
+ }
+ default:
+ if (item.ownerAs<ScriptExpression>())
+ highlightScriptExpressions(item);
+ return true;
+ }
+ Q_UNREACHABLE_RETURN(false);
+}
+
+void HighlightingVisitor::highlightComment(const DomItem &item)
+{
+ const auto comment = item.as<Comment>();
+ Q_ASSERT(comment);
+ const auto locs = HighlightingUtils::sourceLocationsFromMultiLineToken(
+ comment->info().comment(), comment->info().sourceLocation());
+ for (const auto &loc : locs)
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Comment));
+}
+
+void HighlightingVisitor::highlightImport(const DomItem &item)
+{
+ const auto fLocs = FileLocations::treeOf(item);
+ if (!fLocs)
+ return;
+ const auto regions = fLocs->info().regions;
+ const auto import = item.as<Import>();
+ Q_ASSERT(import);
+ m_highlights.addHighlight(regions, ImportTokenRegion);
+ if (import->uri.isModule())
+ m_highlights.addHighlight(regions[ImportUriRegion], int(SemanticTokenTypes::Namespace));
+ else
+ m_highlights.addHighlight(regions[ImportUriRegion], int(SemanticTokenTypes::String));
+ if (regions.contains(VersionRegion))
+ m_highlights.addHighlight(regions, VersionRegion);
+ if (regions.contains(AsTokenRegion)) {
+ m_highlights.addHighlight(regions, AsTokenRegion);
+ m_highlights.addHighlight(regions[IdNameRegion], int(SemanticTokenTypes::Namespace));
+ }
+}
+
+void HighlightingVisitor::highlightBinding(const DomItem &item)
+{
+ const auto binding = item.as<Binding>();
+ Q_ASSERT(binding);
+ const auto fLocs = FileLocations::treeOf(item);
+ if (!fLocs) {
+ qCDebug(semanticTokens) << "Can't find the locations for" << item.internalKind();
+ return;
+ }
+ const auto regions = fLocs->info().regions;
+ // If dotted name, then defer it to be handled in ScriptIdentifierExpression
+ if (binding->name().contains("."_L1))
+ return;
+
+ if (binding->bindingType() != BindingType::Normal) {
+ m_highlights.addHighlight(regions, OnTokenRegion);
+ m_highlights.addHighlight(regions[IdentifierRegion], int(SemanticTokenTypes::Property));
+ return;
+ }
+
+ return highlightBySemanticAnalysis(item, regions[IdentifierRegion]);
+}
+
+void HighlightingVisitor::highlightPragma(const DomItem &item)
+{
+ const auto fLocs = FileLocations::treeOf(item);
+ if (!fLocs)
+ return;
+ const auto regions = fLocs->info().regions;
+ m_highlights.addHighlight(regions, PragmaKeywordRegion);
+ m_highlights.addHighlight(regions, IdentifierRegion);
+ const auto pragma = item.as<Pragma>();
+ for (auto i = 0; i < pragma->values.size(); ++i) {
+ DomItem value = item.field(Fields::values).index(i);
+ const auto valueRegions = FileLocations::treeOf(value)->info().regions;
+ m_highlights.addHighlight(valueRegions, PragmaValuesRegion);
+ }
+ return;
+}
+
+void HighlightingVisitor::highlightEnumDecl(const DomItem &item)
+{
+ const auto fLocs = FileLocations::treeOf(item);
+ if (!fLocs)
+ return;
+ const auto regions = fLocs->info().regions;
+ m_highlights.addHighlight(regions, EnumKeywordRegion);
+ m_highlights.addHighlight(regions[IdentifierRegion], int(SemanticTokenTypes::Enum));
+}
+
+void HighlightingVisitor::highlightEnumItem(const DomItem &item)
+{
+ const auto fLocs = FileLocations::treeOf(item);
+ if (!fLocs)
+ return;
+ const auto regions = fLocs->info().regions;
+ m_highlights.addHighlight(regions[IdentifierRegion], int(SemanticTokenTypes::EnumMember));
+ if (regions.contains(EnumValueRegion))
+ m_highlights.addHighlight(regions, EnumValueRegion);
+}
+
+void HighlightingVisitor::highlightQmlObject(const DomItem &item)
+{
+ const auto qmlObject = item.as<QmlObject>();
+ Q_ASSERT(qmlObject);
+ const auto fLocs = FileLocations::treeOf(item);
+ if (!fLocs)
+ return;
+ const auto regions = fLocs->info().regions;
+ // Handle ids here
+ if (!qmlObject->idStr().isEmpty()) {
+ m_highlights.addHighlight(regions, IdTokenRegion);
+ m_highlights.addHighlight(regions, IdNameRegion);
+ }
+ // If dotted name, then defer it to be handled in ScriptIdentifierExpression
+ if (qmlObject->name().contains("."_L1))
+ return;
+
+ m_highlights.addHighlight(regions[IdentifierRegion], int(SemanticTokenTypes::Type));
+}
+
+void HighlightingVisitor::highlightComponent(const DomItem &item)
+{
+ const auto fLocs = FileLocations::treeOf(item);
+ if (!fLocs)
+ return;
+ const auto regions = fLocs->info().regions;
+ m_highlights.addHighlight(regions, ComponentKeywordRegion);
+ m_highlights.addHighlight(regions[IdentifierRegion], int(SemanticTokenTypes::Type));
+}
+
+void HighlightingVisitor::highlightPropertyDefinition(const DomItem &item)
+{
+ const auto propertyDef = item.as<PropertyDefinition>();
+ Q_ASSERT(propertyDef);
+ const auto fLocs = FileLocations::treeOf(item);
+ if (!fLocs)
+ return;
+ const auto regions = fLocs->info().regions;
+ int modifier = 0;
+ HighlightingUtils::addModifier(SemanticTokenModifiers::Definition, &modifier);
+ if (propertyDef->isDefaultMember) {
+ HighlightingUtils::addModifier(SemanticTokenModifiers::DefaultLibrary,
+ &modifier);
+ m_highlights.addHighlight(regions[DefaultKeywordRegion],
+ int(SemanticTokenTypes::Keyword));
+ }
+ if (propertyDef->isRequired) {
+ HighlightingUtils::addModifier(SemanticTokenModifiers::Abstract, &modifier);
+ m_highlights.addHighlight(regions[RequiredKeywordRegion],
+ int(SemanticTokenTypes::Keyword));
+ }
+ if (propertyDef->isReadonly) {
+ HighlightingUtils::addModifier(SemanticTokenModifiers::Readonly, &modifier);
+ m_highlights.addHighlight(regions[ReadonlyKeywordRegion],
+ int(SemanticTokenTypes::Keyword));
+ }
+ m_highlights.addHighlight(regions, PropertyKeywordRegion);
+ if (propertyDef->isAlias())
+ m_highlights.addHighlight(regions[TypeIdentifierRegion],
+ int(SemanticTokenTypes::Keyword));
+ else
+ m_highlights.addHighlight(regions, TypeIdentifierRegion);
+ m_highlights.addHighlight(regions[IdentifierRegion], int(SemanticTokenTypes::Property),
+ modifier);
+}
+
+void HighlightingVisitor::highlightMethod(const DomItem &item)
+{
+ const auto method = item.as<MethodInfo>();
+ Q_ASSERT(method);
+ const auto fLocs = FileLocations::treeOf(item);
+ if (!fLocs)
+ return;
+ const auto regions = fLocs->info().regions;
+ switch (method->methodType) {
+ case MethodInfo::Signal: {
+ m_highlights.addHighlight(regions, SignalKeywordRegion);
+ m_highlights.addHighlight(regions[IdentifierRegion], int(SemanticTokenTypes::Method));
+ break;
+ }
+ case MethodInfo::Method: {
+ m_highlights.addHighlight(regions, FunctionKeywordRegion);
+ m_highlights.addHighlight(regions[IdentifierRegion], int(SemanticTokenTypes::Method));
+ m_highlights.addHighlight(regions[TypeIdentifierRegion], int(SemanticTokenTypes::Type));
+ break;
+ }
+ default:
+ Q_UNREACHABLE();
+ }
+
+ for (auto i = 0; i < method->parameters.size(); ++i) {
+ DomItem parameter = item.field(Fields::parameters).index(i);
+ const auto paramRegions = FileLocations::treeOf(parameter)->info().regions;
+ m_highlights.addHighlight(paramRegions[IdentifierRegion],
+ int(SemanticTokenTypes::Parameter));
+ m_highlights.addHighlight(paramRegions[TypeIdentifierRegion], int(SemanticTokenTypes::Type));
+ }
+ return;
+}
+
+void HighlightingVisitor::highlightScriptLiteral(const DomItem &item)
+{
+ const auto literal = item.as<ScriptElements::Literal>();
+ Q_ASSERT(literal);
+ const auto fLocs = FileLocations::treeOf(item);
+ if (!fLocs)
+ return;
+ const auto regions = fLocs->info().regions;
+ if (std::holds_alternative<QString>(literal->literalValue())) {
+ const QString value = u'\"' + std::get<QString>(literal->literalValue()) + u'\"';
+ const auto &locs = HighlightingUtils::sourceLocationsFromMultiLineToken(
+ value, regions[MainRegion]);
+ for (const auto &loc : locs)
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::String));
+ } else if (std::holds_alternative<double>(literal->literalValue()))
+ m_highlights.addHighlight(regions[MainRegion], int(SemanticTokenTypes::Number));
+ else if (std::holds_alternative<bool>(literal->literalValue()))
+ m_highlights.addHighlight(regions[MainRegion], int(SemanticTokenTypes::Keyword));
+ else if (std::holds_alternative<std::nullptr_t>(literal->literalValue()))
+ m_highlights.addHighlight(regions[MainRegion], int(SemanticTokenTypes::Keyword));
+ else
+ qCWarning(semanticTokens) << "Invalid literal variant";
+}
+
+void HighlightingVisitor::highlightIdentifier(const DomItem &item)
+{
+ using namespace QLspSpecification;
+ const auto id = item.as<ScriptElements::IdentifierExpression>();
+ Q_ASSERT(id);
+ const auto loc = id->mainRegionLocation();
+ // Many of the scriptIdentifiers expressions are already handled by
+ // other cases. In those cases, if the location offset is already in the list
+ // we don't need to perform expensive resolveExpressionType operation.
+ if (m_highlights.highlights().contains(loc.offset))
+ return;
+
+ highlightBySemanticAnalysis(item, loc);
+}
+
+void HighlightingVisitor::highlightBySemanticAnalysis(const DomItem &item, QQmlJS::SourceLocation loc)
+{
+ const auto expression = QQmlLSUtils::resolveExpressionType(
+ item, QQmlLSUtils::ResolveOptions::ResolveOwnerType);
+
+ if (!expression) {
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Variable));
+ return;
+ }
+ switch (expression->type) {
+ case QQmlLSUtils::QmlComponentIdentifier:
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Type));
+ return;
+ case QQmlLSUtils::JavaScriptIdentifier: {
+ SemanticTokenTypes tokenType = SemanticTokenTypes::Variable;
+ int modifier = 0;
+ if (const auto jsIdentifier
+ = expression->semanticScope->jsIdentifier(expression->name.value())) {
+ switch (jsIdentifier.value().kind) {
+ case QQmlJSScope::JavaScriptIdentifier::Parameter:
+ tokenType = SemanticTokenTypes::Parameter;
+ break;
+ case QQmlJSScope::JavaScriptIdentifier::LexicalScoped: // let or const
+ case QQmlJSScope::JavaScriptIdentifier::FunctionScoped: // var
+ case QQmlJSScope::JavaScriptIdentifier::Injected:
+ default:
+ tokenType = SemanticTokenTypes::Variable;
+ break;
+ }
+ if (jsIdentifier.value().isConst) {
+ HighlightingUtils::addModifier(SemanticTokenModifiers::Readonly,
+ &modifier);
+ }
+ }
+ m_highlights.addHighlight(loc, int(tokenType), modifier);
+ return;
+ }
+ case QQmlLSUtils::PropertyIdentifier: {
+ if (const auto scope = expression->semanticScope) {
+ const auto property = scope->property(expression->name.value());
+ int modifier = 0;
+ if (!property.isWritable()) {
+ HighlightingUtils::addModifier(SemanticTokenModifiers::Readonly,
+ &modifier);
+ }
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Property), modifier);
+ }
+ return;
+ }
+ case QQmlLSUtils::PropertyChangedSignalIdentifier:
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Method));
+ return;
+ case QQmlLSUtils::PropertyChangedHandlerIdentifier:
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Method));
+ return;
+ case QQmlLSUtils::SignalIdentifier:
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Method));
+ return;
+ case QQmlLSUtils::SignalHandlerIdentifier:
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Method));
+ return;
+ case QQmlLSUtils::MethodIdentifier:
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Method));
+ return;
+ case QQmlLSUtils::QmlObjectIdIdentifier:
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Variable));
+ return;
+ case QQmlLSUtils::SingletonIdentifier:
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Type));
+ return;
+ case QQmlLSUtils::EnumeratorIdentifier:
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Enum));
+ return;
+ case QQmlLSUtils::EnumeratorValueIdentifier:
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::EnumMember));
+ return;
+ case QQmlLSUtils::AttachedTypeIdentifier:
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Type));
+ return;
+ case QQmlLSUtils::GroupedPropertyIdentifier:
+ m_highlights.addHighlight(loc, int(SemanticTokenTypes::Property));
+ return;
+ default:
+ qCWarning(semanticTokens)
+ << QString::fromLatin1("Semantic token for %1 has not been implemented yet")
+ .arg(int(expression->type));
+ }
+ Q_UNREACHABLE_RETURN();
+}
+
+void HighlightingVisitor::highlightScriptExpressions(const DomItem &item)
+{
+ const auto fLocs = FileLocations::treeOf(item);
+ if (!fLocs)
+ return;
+ const auto regions = fLocs->info().regions;
+ switch (item.internalKind()) {
+ case DomType::ScriptLiteral:
+ highlightScriptLiteral(item);
+ return;
+ case DomType::ScriptForStatement:
+ m_highlights.addHighlight(regions, ForKeywordRegion);
+ m_highlights.addHighlight(regions[TypeIdentifierRegion],
+ int(SemanticTokenTypes::Keyword));
+ return;
+
+ case DomType::ScriptVariableDeclaration: {
+ m_highlights.addHighlight(regions[TypeIdentifierRegion],
+ int(SemanticTokenTypes::Keyword));
+ return;
+ }
+ case DomType::ScriptReturnStatement:
+ m_highlights.addHighlight(regions, ReturnKeywordRegion);
+ return;
+ case DomType::ScriptCaseClause:
+ m_highlights.addHighlight(regions, CaseKeywordRegion);
+ return;
+ case DomType::ScriptDefaultClause:
+ m_highlights.addHighlight(regions, DefaultKeywordRegion);
+ return;
+ case DomType::ScriptSwitchStatement:
+ m_highlights.addHighlight(regions, SwitchKeywordRegion);
+ return;
+ case DomType::ScriptWhileStatement:
+ m_highlights.addHighlight(regions, WhileKeywordRegion);
+ return;
+ case DomType::ScriptDoWhileStatement:
+ m_highlights.addHighlight(regions, DoKeywordRegion);
+ m_highlights.addHighlight(regions, WhileKeywordRegion);
+ return;
+ case DomType::ScriptTryCatchStatement:
+ m_highlights.addHighlight(regions, TryKeywordRegion);
+ m_highlights.addHighlight(regions, CatchKeywordRegion);
+ m_highlights.addHighlight(regions, FinallyKeywordRegion);
+ return;
+ case DomType::ScriptForEachStatement:
+ m_highlights.addHighlight(regions[TypeIdentifierRegion],
+ int(SemanticTokenTypes::Keyword));
+ m_highlights.addHighlight(regions, ForKeywordRegion);
+ m_highlights.addHighlight(regions, InOfTokenRegion);
+ return;
+ case DomType::ScriptThrowStatement:
+ m_highlights.addHighlight(regions, ThrowKeywordRegion);
+ return;
+ case DomType::ScriptBreakStatement:
+ m_highlights.addHighlight(regions, BreakKeywordRegion);
+ return;
+ case DomType::ScriptContinueStatement:
+ m_highlights.addHighlight(regions, ContinueKeywordRegion);
+ return;
+ case DomType::ScriptIfStatement:
+ m_highlights.addHighlight(regions, IfKeywordRegion);
+ m_highlights.addHighlight(regions, ElseKeywordRegion);
+ return;
+ case DomType::ScriptLabelledStatement:
+ m_highlights.addHighlight(regions, IdentifierRegion);
+ return;
+ case DomType::ScriptConditionalExpression:
+ m_highlights.addHighlight(regions, QuestionMarkTokenRegion);
+ m_highlights.addHighlight(regions, ColonTokenRegion);
+ return;
+ case DomType::ScriptUnaryExpression:
+ case DomType::ScriptPostExpression:
+ m_highlights.addHighlight(regions, OperatorTokenRegion);
+ return;
+ case DomType::ScriptType:
+ m_highlights.addHighlight(regions[IdentifierRegion], int(SemanticTokenTypes::Type));
+ m_highlights.addHighlight(regions[TypeIdentifierRegion], int(SemanticTokenTypes::Type));
+ return;
+ default:
+ qCDebug(semanticTokens)
+ << "Script Expressions with kind" << item.internalKind() << "not implemented";
+ return;
+ }
+ Q_UNREACHABLE_RETURN();
+}
+
+/*!
+\internal
+\brief Returns multiple source locations for a given raw comment
+
+Needed by semantic highlighting of comments. LSP clients usually don't support multiline
+tokens. In QML, we can have multiline tokens like string literals and comments.
+This method generates multiple source locations of sub-elements of token split by a newline
+delimiter.
+*/
+QList<QQmlJS::SourceLocation>
+HighlightingUtils::sourceLocationsFromMultiLineToken(QStringView stringLiteral,
+ const QQmlJS::SourceLocation &locationInDocument)
+{
+ auto lineBreakLength = qsizetype(std::char_traits<char>::length("\n"));
+ const auto lineLengths = [&lineBreakLength](QStringView literal) {
+ std::vector<qsizetype> lineLengths;
+ qsizetype startIndex = 0;
+ qsizetype pos = literal.indexOf(u'\n');
+ while (pos != -1) {
+ // TODO: QTBUG-106813
+ // Since a document could be opened in normalized form
+ // we can't use platform dependent newline handling here.
+ // Thus, we check manually if the literal contains \r so that we split
+ // the literal at the correct offset.
+ if (pos - 1 > 0 && literal[pos - 1] == u'\r') {
+ // Handle Windows line endings
+ lineBreakLength = qsizetype(std::char_traits<char>::length("\r\n"));
+ // Move pos to the index of '\r'
+ pos = pos - 1;
+ }
+ lineLengths.push_back(pos - startIndex);
+ // Advance the lookup index, so it won't find the same index.
+ startIndex = pos + lineBreakLength;
+ pos = literal.indexOf('\n'_L1, startIndex);
+ }
+ // Push the last line
+ if (startIndex < literal.length()) {
+ lineLengths.push_back(literal.length() - startIndex);
+ }
+ return lineLengths;
+ };
+
+ QList<QQmlJS::SourceLocation> result;
+ // First token location should start from the "stringLiteral"'s
+ // location in the qml document.
+ QQmlJS::SourceLocation lineLoc = locationInDocument;
+ for (const auto lineLength : lineLengths(stringLiteral)) {
+ lineLoc.length = lineLength;
+ result.push_back(lineLoc);
+
+ // update for the next line
+ lineLoc.offset += lineLoc.length + lineBreakLength;
+ ++lineLoc.startLine;
+ lineLoc.startColumn = 1;
+ }
+ return result;
+}
+
+QList<int> HighlightingUtils::encodeSemanticTokens(Highlights &highlights)
+{
+ QList<int> result;
+ const auto highlightingTokens = highlights.highlights();
+ constexpr auto tokenEncodingLength = 5;
+ result.reserve(tokenEncodingLength * highlightingTokens.size());
+
+ int prevLine = 0;
+ int prevColumn = 0;
+
+ std::for_each(highlightingTokens.constBegin(), highlightingTokens.constEnd(), [&](const auto &token) {
+ Q_ASSERT(token.startLine >= prevLine);
+ if (token.startLine != prevLine)
+ prevColumn = 0;
+ result.emplace_back(token.startLine - prevLine);
+ result.emplace_back(token.startColumn - prevColumn);
+ result.emplace_back(token.length);
+ result.emplace_back(token.tokenType);
+ result.emplace_back(token.tokenModifier);
+ prevLine = token.startLine;
+ prevColumn = token.startColumn;
+ });
+
+ return result;
+}
+
+/*!
+\internal
+Computes the modifier value. Modifier is read as binary value in the protocol. The location
+of the bits set are interpreted as the indices of the tokenModifiers list registered by the
+server. Then, the client modifies the highlighting of the token.
+
+tokenModifiersList: ["declaration", definition, readonly, static ,,,]
+
+To set "definition" and "readonly", we need to send 0b00000110
+*/
+void HighlightingUtils::addModifier(SemanticTokenModifiers modifier, int *baseModifier)
+{
+ if (!baseModifier)
+ return;
+ *baseModifier |= (1 << int(modifier));
+}
+
+/*!
+\internal
+Check if the ranges overlap by ensuring that one range starts before the other ends
+*/
+bool HighlightingUtils::rangeOverlapsWithSourceLocation(const QQmlJS::SourceLocation &loc,
+ const HighlightsRange &r)
+{
+ int startOffsetItem = int(loc.offset);
+ int endOffsetItem = startOffsetItem + int(loc.length);
+ return (startOffsetItem <= r.endOffset) && (r.startOffset <= endOffsetItem);
+}
+
+/*
+\internal
+Increments the resultID by one.
+*/
+void HighlightingUtils::updateResultID(QByteArray &resultID)
+{
+ int length = resultID.length();
+ for (int i = length - 1; i >= 0; --i) {
+ if (resultID[i] == '9') {
+ resultID[i] = '0';
+ } else {
+ resultID[i] = resultID[i] + 1;
+ return;
+ }
+ }
+ resultID.prepend('1');
+}
+
+/*
+\internal
+A utility method that computes the difference of two list. The first argument is the encoded token data
+of the file before edited. The second argument is the encoded token data after the file is edited. Returns
+a list of SemanticTokensEdit as expected by the protocol.
+*/
+QList<SemanticTokensEdit> HighlightingUtils::computeDiff(const QList<int> &oldData, const QList<int> &newData)
+{
+ // Find the iterators pointing the first mismatch, from the start
+ const auto [oldStart, newStart] =
+ std::mismatch(oldData.cbegin(), oldData.cend(), newData.cbegin(), newData.cend());
+
+ // Find the iterators pointing the first mismatch, from the end
+ // but the iterators shouldn't pass over the start iterators found above.
+ const auto [r1, r2] = std::mismatch(oldData.crbegin(), std::make_reverse_iterator(oldStart),
+ newData.crbegin(), std::make_reverse_iterator(newStart));
+ const auto oldEnd = r1.base();
+ const auto newEnd = r2.base();
+
+ // no change
+ if (oldStart == oldEnd && newStart == newEnd)
+ return {};
+
+ SemanticTokensEdit edit;
+ edit.start = int(std::distance(newData.cbegin(), newStart));
+ edit.deleteCount = int(std::distance(oldStart, oldEnd));
+
+ if (newStart >= newData.cbegin() && newEnd <= newData.cend() && newStart < newEnd)
+ edit.data.emplace(newStart, newEnd);
+
+ return { std::move(edit) };
+}
+
+
+void Highlights::addHighlight(const QQmlJS::SourceLocation &loc, int tokenType, int tokenModifier)
+{
+ if (!loc.isValid()) {
+ qCDebug(semanticTokens) << "Invalid locations: Cannot add highlight to token";
+ return;
+ }
+
+ if (!m_highlights.contains(loc.offset))
+ m_highlights.insert(loc.offset, QT_PREPEND_NAMESPACE(Token)(loc, tokenType, tokenModifier));
+}
+
+void Highlights::addHighlight(const QMap<FileLocationRegion, QQmlJS::SourceLocation> &regions,
+ FileLocationRegion region, int modifier)
+{
+ if (!regions.contains(region)) {
+ qCDebug(semanticTokens) << "Invalid region: Cannot add highlight to token";
+ return;
+ }
+
+ const auto loc = regions.value(region);
+ return addHighlight(loc, tokenTypeFromRegion(region), modifier);
+}
+
+QList<int> Highlights::collectTokens(const QQmlJS::Dom::DomItem &item,
+ const std::optional<HighlightsRange> &range)
+{
+ using namespace QQmlJS::Dom;
+ HighlightingVisitor highlightDomElements(*this, range);
+ // In QmlFile level, visitTree visits even FileLocations tree which takes quite a time to
+ // finish. HighlightingFilter is added to prevent unnecessary visits.
+ item.visitTree(Path(), highlightDomElements, VisitOption::Default, emptyChildrenVisitor,
+ emptyChildrenVisitor, highlightingFilter());
+
+ return HighlightingUtils::encodeSemanticTokens(*this);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmlls/qqmlsemantictokens_p.h b/src/qmlls/qqmlsemantictokens_p.h
new file mode 100644
index 0000000000..193c39baea
--- /dev/null
+++ b/src/qmlls/qqmlsemantictokens_p.h
@@ -0,0 +1,131 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLSEMANTICTOKENS_P_H
+#define QQMLSEMANTICTOKENS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLanguageServer/private/qlanguageserverspec_p.h>
+#include <QtQmlDom/private/qqmldomitem_p.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmap.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(semanticTokens)
+
+// Represents a semantic highlighting token
+// startLine and startColumn are 0-based as in LSP spec.
+struct Token
+{
+ Token() = default;
+ Token(const QQmlJS::SourceLocation &loc, int tokenType, int tokenModifier = 0)
+ : offset(loc.offset),
+ length(loc.length),
+ startLine(loc.startLine - 1),
+ startColumn(loc.startColumn - 1),
+ tokenType(tokenType),
+ tokenModifier(tokenModifier)
+ {
+ }
+
+ inline friend bool operator<(const Token &lhs, const Token &rhs)
+ {
+ return lhs.offset < rhs.offset;
+ }
+
+ inline friend bool operator==(const Token &lhs, const Token &rhs)
+ {
+ return lhs.offset == rhs.offset && lhs.length == rhs.length
+ && lhs.startLine == rhs.startLine && lhs.startColumn == rhs.startColumn
+ && lhs.tokenType == rhs.tokenType && lhs.tokenModifier == rhs.tokenModifier;
+ }
+
+ int offset;
+ int length;
+ int startLine;
+ int startColumn;
+ int tokenType;
+ int tokenModifier;
+};
+
+using HighlightsContainer = QMap<int, QT_PREPEND_NAMESPACE(Token)>;
+
+/*!
+\internal
+Offsets start from zero.
+*/
+struct HighlightsRange
+{
+ int startOffset;
+ int endOffset;
+};
+
+class Highlights
+{
+public:
+ void addHighlight(const QQmlJS::SourceLocation &loc, int tokenType, int tokenModifier = 0);
+ void addHighlight(const QMap<QQmlJS::Dom::FileLocationRegion, QQmlJS::SourceLocation> &regions,
+ QQmlJS::Dom::FileLocationRegion region, int tokenModifier = 0);
+ QList<int> collectTokens(const QQmlJS::Dom::DomItem &item,
+ const std::optional<HighlightsRange> &range);
+
+ HighlightsContainer &highlights() { return m_highlights; }
+ const HighlightsContainer &highlights() const { return m_highlights; }
+
+private:
+ HighlightsContainer m_highlights;
+};
+
+struct HighlightingUtils
+{
+ static QList<int> encodeSemanticTokens(Highlights &highlights);
+ static QList<QQmlJS::SourceLocation>
+ sourceLocationsFromMultiLineToken(QStringView code,
+ const QQmlJS::SourceLocation &tokenLocation);
+ static void addModifier(QLspSpecification::SemanticTokenModifiers modifier, int *baseModifier);
+ static bool rangeOverlapsWithSourceLocation(const QQmlJS::SourceLocation &loc, const HighlightsRange &r);
+ static QList<QLspSpecification::SemanticTokensEdit> computeDiff(const QList<int> &, const QList<int> &);
+ static void updateResultID(QByteArray &resultID);
+};
+
+class HighlightingVisitor
+{
+public:
+ HighlightingVisitor(Highlights &highlights, const std::optional<HighlightsRange> &range);
+ bool operator()(QQmlJS::Dom::Path, const QQmlJS::Dom::DomItem &item, bool);
+
+private:
+ void highlightComment(const QQmlJS::Dom::DomItem &item);
+ void highlightImport(const QQmlJS::Dom::DomItem &item);
+ void highlightBinding(const QQmlJS::Dom::DomItem &item);
+ void highlightPragma(const QQmlJS::Dom::DomItem &item);
+ void highlightEnumItem(const QQmlJS::Dom::DomItem &item);
+ void highlightEnumDecl(const QQmlJS::Dom::DomItem &item);
+ void highlightQmlObject(const QQmlJS::Dom::DomItem &item);
+ void highlightComponent(const QQmlJS::Dom::DomItem &item);
+ void highlightPropertyDefinition(const QQmlJS::Dom::DomItem &item);
+ void highlightMethod(const QQmlJS::Dom::DomItem &item);
+ void highlightScriptLiteral(const QQmlJS::Dom::DomItem &item);
+ void highlightIdentifier(const QQmlJS::Dom::DomItem &item);
+ void highlightBySemanticAnalysis(const QQmlJS::Dom::DomItem &item, QQmlJS::SourceLocation loc);
+ void highlightScriptExpressions(const QQmlJS::Dom::DomItem &item);
+
+private:
+ Highlights &m_highlights;
+ std::optional<HighlightsRange> m_range;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLSEMANTICTOKENS_P_H
diff --git a/src/qmlmodels/CMakeLists.txt b/src/qmlmodels/CMakeLists.txt
index 18ae5ceeff..9a9202e6ed 100644
--- a/src/qmlmodels/CMakeLists.txt
+++ b/src/qmlmodels/CMakeLists.txt
@@ -12,7 +12,7 @@ qt_internal_add_qml_module(QmlModels
PLUGIN_TARGET modelsplugin
CLASS_NAME QtQmlModelsPlugin
DEPENDENCIES
- QtQml.Base/auto
+ QML/1.0
SOURCES
qqmlchangeset.cpp qqmlchangeset_p.h
qqmlmodelsmodule.cpp qqmlmodelsmodule_p.h
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index e24c10b786..3df3f09336 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -31,7 +31,7 @@ namespace QV4 {
namespace Heap {
struct DelegateModelGroupFunction : FunctionObject {
- void init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg));
+ void init(ExecutionEngine *engine, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg));
QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg);
uint flag;
@@ -60,9 +60,11 @@ struct DelegateModelGroupFunction : QV4::FunctionObject
{
V4_OBJECT2(DelegateModelGroupFunction, FunctionObject)
- static Heap::DelegateModelGroupFunction *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
+ static Heap::DelegateModelGroupFunction *create(
+ QV4::ExecutionEngine *engine, uint flag,
+ QV4::ReturnedValue (*code)(QQmlDelegateModelItem *, uint, const QV4::Value &))
{
- return scope->engine()->memoryManager->allocate<DelegateModelGroupFunction>(scope, flag, code);
+ return engine->memoryManager->allocate<DelegateModelGroupFunction>(engine, flag, code);
}
static ReturnedValue virtualCall(const QV4::FunctionObject *that, const Value *thisObject, const Value *argv, int argc)
@@ -78,9 +80,11 @@ struct DelegateModelGroupFunction : QV4::FunctionObject
}
};
-void Heap::DelegateModelGroupFunction::init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
+void Heap::DelegateModelGroupFunction::init(
+ QV4::ExecutionEngine *engine, uint flag,
+ QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
{
- QV4::Heap::FunctionObject::init(scope, QStringLiteral("DelegateModelGroupFunction"));
+ QV4::Heap::FunctionObject::init(engine, QStringLiteral("DelegateModelGroupFunction"));
this->flag = flag;
this->code = code;
}
@@ -1887,12 +1891,16 @@ void QQmlDelegateModelPrivate::emitChanges()
void QQmlDelegateModel::_q_modelAboutToBeReset()
{
- auto aim = static_cast<QAbstractItemModel *>(sender());
+ Q_D(QQmlDelegateModel);
+ if (!d->m_adaptorModel.adaptsAim())
+ return;
+ auto aim = d->m_adaptorModel.aim();
auto oldRoleNames = aim->roleNames();
// this relies on the fact that modelAboutToBeReset must be followed
// by a modelReset signal before any further modelAboutToBeReset can occur
- QObject::connect(aim, &QAbstractItemModel::modelReset, this, [&, oldRoleNames](){
- auto aim = static_cast<QAbstractItemModel *>(sender());
+ QObject::connect(aim, &QAbstractItemModel::modelReset, this, [this, d, oldRoleNames, aim](){
+ if (!d->m_adaptorModel.adaptsAim() || d->m_adaptorModel.aim() != aim)
+ return;
if (oldRoleNames == aim->roleNames()) {
// if the rolenames stayed the same (most common case), then we don't have
// to throw away all the setup that we did
@@ -2187,27 +2195,27 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
s = v4Engine->newString(QStringLiteral("isUnresolved"));
QV4::ScopedFunctionObject f(scope);
- QV4::ExecutionContext *global = scope.engine->rootContext();
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, 30, QQmlDelegateModelItem::get_member)));
+ QV4::ExecutionEngine *engine = scope.engine;
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, 30, QQmlDelegateModelItem::get_member)));
p->setSetter(nullptr);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("inItems"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("inPersistedItems"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("itemsIndex"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("persistedItemsIndex"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index)));
p->setSetter(nullptr);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
@@ -2215,14 +2223,14 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
QString propertyName = QLatin1String("in") + groupNames.at(i);
propertyName.replace(2, 1, propertyName.at(2).toUpper());
s = v4Engine->newString(propertyName);
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::set_member)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, i + 1, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = QV4::DelegateModelGroupFunction::create(engine, i + 1, QQmlDelegateModelItem::set_member)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
for (int i = 2; i < groupNames.size(); ++i) {
const QString propertyName = groupNames.at(i) + QLatin1String("Index");
s = v4Engine->newString(propertyName);
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_index)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, i + 1, QQmlDelegateModelItem::get_index)));
p->setSetter(nullptr);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
diff --git a/src/qmlmodels/qqmldmabstractitemmodeldata_p.h b/src/qmlmodels/qqmldmabstractitemmodeldata_p.h
index e3769b6d98..2994b59730 100644
--- a/src/qmlmodels/qqmldmabstractitemmodeldata_p.h
+++ b/src/qmlmodels/qqmldmabstractitemmodeldata_p.h
@@ -188,9 +188,14 @@ public:
const QByteArray &propertyName = it.key();
QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName)));
- QV4::ExecutionContext *global = v4->rootContext();
- QV4::ScopedFunctionObject g(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMAbstractItemModelData::get_property));
- QV4::ScopedFunctionObject s(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMAbstractItemModelData::set_property));
+ QV4::ScopedFunctionObject g(
+ scope,
+ v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(
+ v4, propertyId, QQmlDMAbstractItemModelData::get_property));
+ QV4::ScopedFunctionObject s(
+ scope,
+ v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(
+ v4, propertyId, QQmlDMAbstractItemModelData::set_property));
p->setGetter(g);
p->setSetter(s);
proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
diff --git a/src/qmltest/doc/snippets/testApp/CMakeLists.txt b/src/qmltest/doc/snippets/testApp/CMakeLists.txt
index 71eb6bebb7..cdf7b9555e 100644
--- a/src/qmltest/doc/snippets/testApp/CMakeLists.txt
+++ b/src/qmltest/doc/snippets/testApp/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.20)
diff --git a/src/qmltest/doc/snippets/testApp/MyModule/CMakeLists.txt b/src/qmltest/doc/snippets/testApp/MyModule/CMakeLists.txt
index dbbbbd45b0..4d293c27d8 100644
--- a/src/qmltest/doc/snippets/testApp/MyModule/CMakeLists.txt
+++ b/src/qmltest/doc/snippets/testApp/MyModule/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.20)
diff --git a/src/qmltest/doc/snippets/testApp/tests/CMakeLists.txt b/src/qmltest/doc/snippets/testApp/tests/CMakeLists.txt
index 3255a919f2..5533403bdc 100644
--- a/src/qmltest/doc/snippets/testApp/tests/CMakeLists.txt
+++ b/src/qmltest/doc/snippets/testApp/tests/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.2)
diff --git a/src/qmltest/doc/snippets/testApp/tests/main.cpp b/src/qmltest/doc/snippets/testApp/tests/main.cpp
index d9f1cd68ed..cf68ddb5de 100644
--- a/src/qmltest/doc/snippets/testApp/tests/main.cpp
+++ b/src/qmltest/doc/snippets/testApp/tests/main.cpp
@@ -1,5 +1,5 @@
// # Copyright (C) 2023 The Qt Company Ltd.
-// # SPDX-License-Identifier: BSD-3-Clause
+// # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [main]
#include <QtQuickTest/quicktest.h>
diff --git a/src/qmltest/doc/snippets/testApp/tests/setup.cpp b/src/qmltest/doc/snippets/testApp/tests/setup.cpp
index 92ef206e26..4ecac48d35 100644
--- a/src/qmltest/doc/snippets/testApp/tests/setup.cpp
+++ b/src/qmltest/doc/snippets/testApp/tests/setup.cpp
@@ -1,5 +1,5 @@
// # Copyright (C) 2023 The Qt Company Ltd.
-// # SPDX-License-Identifier: BSD-3-Clause
+// # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [setup]
#include "setup.h"
diff --git a/src/qmltest/doc/snippets/testApp/tests/setup.h b/src/qmltest/doc/snippets/testApp/tests/setup.h
index b6c5248667..ea6a699f2f 100644
--- a/src/qmltest/doc/snippets/testApp/tests/setup.h
+++ b/src/qmltest/doc/snippets/testApp/tests/setup.h
@@ -1,5 +1,5 @@
// # Copyright (C) 2023 The Qt Company Ltd.
-// # SPDX-License-Identifier: BSD-3-Clause
+// # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [setup]
#ifndef SETUP_H
diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp
index ce29dadb47..1a580f8c69 100644
--- a/src/qmltest/quicktest.cpp
+++ b/src/qmltest/quicktest.cpp
@@ -32,6 +32,8 @@
#include <QtGui/qtextdocument.h>
#include <stdio.h>
#include <QtGui/QGuiApplication>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformintegration.h>
#include <QtCore/QTranslator>
#include <QtTest/QSignalSpy>
#include <QtQml/QQmlFileSelector>
@@ -658,10 +660,12 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch
qWarning().nospace()
<< "Test '" << QDir::toNativeSeparators(path) << "' window not exposed after show().";
}
- view.requestActivate();
- if (!QTest::qWaitForWindowActive(&view)) {
- qWarning().nospace()
- << "Test '" << QDir::toNativeSeparators(path) << "' window not active after requestActivate().";
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) {
+ view.requestActivate();
+ if (!QTest::qWaitForWindowActive(&view)) {
+ qWarning().nospace()
+ << "Test '" << QDir::toNativeSeparators(path) << "' window not active after requestActivate().";
+ }
}
if (view.isExposed()) {
// Defer property update until event loop has started
diff --git a/src/qmltoolingsettings/qqmltoolingsettings.cpp b/src/qmltoolingsettings/qqmltoolingsettings.cpp
index 3f5aecccfb..5f8b92a8d2 100644
--- a/src/qmltoolingsettings/qqmltoolingsettings.cpp
+++ b/src/qmltoolingsettings/qqmltoolingsettings.cpp
@@ -39,6 +39,7 @@ bool QQmlToolingSettings::read(const QString &settingsFilePath)
return true;
#else
+ Q_UNUSED(settingsFilePath);
return false;
#endif
}
@@ -118,6 +119,7 @@ bool QQmlToolingSettings::search(const QString &path)
m_seenDirectories[dir] = QString();
#endif
+ Q_UNUSED(path);
return false;
}
diff --git a/src/qmltyperegistrar/qmetatypesjsonprocessor.cpp b/src/qmltyperegistrar/qmetatypesjsonprocessor.cpp
index 480d4ba187..8101b727b9 100644
--- a/src/qmltyperegistrar/qmetatypesjsonprocessor.cpp
+++ b/src/qmltyperegistrar/qmetatypesjsonprocessor.cpp
@@ -152,6 +152,7 @@ void MetaTypesJsonProcessor::postProcessForeignTypes()
{
sortTypes(m_foreignTypes);
sortStringList(&m_primitiveTypes);
+ sortStringList(&m_usingDeclarations);
addRelatedTypes();
sortStringList(&m_referencedTypes);
sortStringList(&m_includes);
@@ -227,8 +228,9 @@ MetaTypesJsonProcessor::PreProcessResult MetaTypesJsonProcessor::preProcess(
// and is not the root object, then it's foreign type has no entry of its own.
// In that case we need to generate a "primitive" entry.
- QList<QAnyStringView> aliases;
- QAnyStringView foreign;
+ QList<QAnyStringView> primitiveAliases;
+ UsingDeclaration usingDeclaration;
+
RegistrationMode mode = NoRegistration;
bool isSelfExtendingValueType = false;
bool hasJavaScriptExtension = false;
@@ -237,9 +239,9 @@ MetaTypesJsonProcessor::PreProcessResult MetaTypesJsonProcessor::preProcess(
for (const ClassInfo &classInfo : classDef.classInfos()) {
if (classInfo.name == S_FOREIGN)
- foreign = classInfo.value;
+ usingDeclaration.alias = classInfo.value;
else if (classInfo.name == S_PRIMITIVE_ALIAS)
- aliases.append(classInfo.value);
+ primitiveAliases.append(classInfo.value);
else if (classInfo.name == S_EXTENSION_IS_JAVA_SCRIPT)
hasJavaScriptExtension = (classInfo.value == S_TRUE);
else if (classInfo.name == S_EXTENDED && classDef.kind() == MetaType::Kind::Gadget)
@@ -248,6 +250,8 @@ MetaTypesJsonProcessor::PreProcessResult MetaTypesJsonProcessor::preProcess(
isRootObject = (classInfo.value == S_TRUE);
else if (classInfo.name == S_SEQUENCE)
isSequence = true;
+ else if (classInfo.name == S_USING)
+ usingDeclaration.original = classInfo.value;
else if (populateMode == PopulateMode::Yes && classInfo.name == S_ELEMENT) {
switch (classDef.kind()) {
case MetaType::Kind::Object:
@@ -270,9 +274,10 @@ MetaTypesJsonProcessor::PreProcessResult MetaTypesJsonProcessor::preProcess(
}
return PreProcessResult {
- aliases,
+ std::move(primitiveAliases),
+ usingDeclaration,
(!isRootObject && (isSequence || isSelfExtendingValueType || hasJavaScriptExtension))
- ? foreign
+ ? usingDeclaration.alias
: QAnyStringView(),
mode
};
@@ -353,10 +358,13 @@ void MetaTypesJsonProcessor::addRelatedTypes()
addRelatedType(foreignType);
seenQmlPrefix = true;
}
- if (name == S_FOREIGN) {
- const QAnyStringView foreign = obj.value;
- if (!addRelatedName(foreign, namespaces(foreignType)))
- unresolvedForeignNames.insert(foreign);
+ if (name == S_FOREIGN
+ || name == S_EXTENDED
+ || name == S_ATTACHED
+ || name == S_SEQUENCE) {
+ ResolvedTypeAlias foreign(obj.value, m_usingDeclarations);
+ if (!addRelatedName(foreign.type, namespaces(foreignType)))
+ unresolvedForeignNames.insert(foreign.type);
break;
}
}
@@ -517,7 +525,7 @@ void MetaTypesJsonProcessor::addRelatedTypes()
const auto addProperties = [&](const MetaType &context,
const QList<QAnyStringView> &namespaces) {
for (const Property &property : context.properties()) {
- ResolvedTypeAlias resolved(property.type);
+ ResolvedTypeAlias resolved(property.type, m_usingDeclarations);
if (!resolved.type.isEmpty())
addType(context, resolved.type, namespaces, "property");
}
@@ -529,12 +537,12 @@ void MetaTypesJsonProcessor::addRelatedTypes()
: {context.methods(), context.constructors(), context.sigs() }) {
for (const Method &methodObject : methods) {
for (const Argument &argument : std::as_const(methodObject.arguments)) {
- ResolvedTypeAlias resolved(argument.type);
+ ResolvedTypeAlias resolved(argument.type, m_usingDeclarations);
if (!resolved.type.isEmpty())
addType(context, resolved.type, namespaces, "argument");
}
- ResolvedTypeAlias resolved(methodObject.returnType);
+ ResolvedTypeAlias resolved(methodObject.returnType, m_usingDeclarations);
if (!resolved.type.isEmpty())
addType(context, resolved.type, namespaces, "return");
}
@@ -544,7 +552,7 @@ void MetaTypesJsonProcessor::addRelatedTypes()
const auto addEnums = [&](const MetaType &context,
const QList<QAnyStringView> &namespaces) {
for (const Enum &enumerator : context.enums()) {
- ResolvedTypeAlias resolved(enumerator.type);
+ ResolvedTypeAlias resolved(enumerator.type, m_usingDeclarations);
if (!resolved.type.isEmpty())
addType(context, resolved.type, namespaces, "enum");
}
@@ -557,7 +565,7 @@ void MetaTypesJsonProcessor::addRelatedTypes()
addType(classDef, obj.value, namespaces, "attached");
return true;
} else if (objNameValue == S_SEQUENCE) {
- ResolvedTypeAlias value(obj.value);
+ ResolvedTypeAlias value(obj.value, m_usingDeclarations);
addType(classDef, value.type, namespaces, "sequence value");
return true;
} else if (objNameValue == S_EXTENDED) {
@@ -675,6 +683,9 @@ void MetaTypesJsonProcessor::processTypes(const QCborMap &types)
m_primitiveTypes.emplaceBack(preprocessed.foreignPrimitive);
m_primitiveTypes.append(preprocessed.primitiveAliases);
}
+
+ if (preprocessed.usingDeclaration.isValid())
+ m_usingDeclarations.append(preprocessed.usingDeclaration);
}
}
@@ -691,6 +702,9 @@ void MetaTypesJsonProcessor::processForeignTypes(const QCborMap &types)
m_primitiveTypes.emplaceBack(preprocessed.foreignPrimitive);
m_primitiveTypes.append(preprocessed.primitiveAliases);
}
+
+ if (preprocessed.usingDeclaration.isValid())
+ m_usingDeclarations.append(preprocessed.usingDeclaration);
}
}
@@ -815,7 +829,7 @@ MetaTypePrivate::MetaTypePrivate(const QCborMap &cbor, const QString &inputFile)
for (const QCborValue &property : cborProperties)
properties.emplace_back(property.toMap());
- for (const QCborArray &cborMethods : { cbor[S_METHODS].toArray(), cbor[S_SLOTS].toArray() }) {
+ for (const QCborArray &cborMethods : { cbor[S_SLOTS].toArray(), cbor[S_METHODS].toArray() }) {
for (const QCborValue &method : cborMethods)
methods.emplace_back(method.toMap(), false);
}
diff --git a/src/qmltyperegistrar/qmetatypesjsonprocessor_p.h b/src/qmltyperegistrar/qmetatypesjsonprocessor_p.h
index 9d86665c52..f582cf7a1e 100644
--- a/src/qmltyperegistrar/qmetatypesjsonprocessor_p.h
+++ b/src/qmltyperegistrar/qmetatypesjsonprocessor_p.h
@@ -209,6 +209,27 @@ private:
const MetaTypePrivate *d = &s_empty;
};
+struct UsingDeclaration {
+ QAnyStringView alias;
+ QAnyStringView original;
+
+ bool isValid() const { return !alias.isEmpty() && !original.isEmpty(); }
+private:
+ friend bool comparesEqual(const UsingDeclaration &a, const UsingDeclaration &b) noexcept
+ {
+ return std::tie(a.alias, a.original) == std::tie(b.alias, b.original);
+ }
+
+ friend Qt::strong_ordering compareThreeWay(
+ const UsingDeclaration &a, const UsingDeclaration &b) noexcept
+ {
+ return a.alias != b.alias
+ ? compareThreeWay(a.alias, b.alias)
+ : compareThreeWay(a.original, b.original);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(UsingDeclaration);
+};
+
class MetaTypesJsonProcessor
{
public:
@@ -227,6 +248,7 @@ public:
QVector<MetaType> types() const { return m_types; }
QVector<MetaType> foreignTypes() const { return m_foreignTypes; }
QList<QAnyStringView> referencedTypes() const { return m_referencedTypes; }
+ QList<UsingDeclaration> usingDeclarations() const { return m_usingDeclarations; }
QList<QString> includes() const { return m_includes; }
QString extractRegisteredTypes() const;
@@ -241,15 +263,11 @@ private:
struct PreProcessResult {
QList<QAnyStringView> primitiveAliases;
+ UsingDeclaration usingDeclaration;
QAnyStringView foreignPrimitive;
RegistrationMode mode;
};
- struct PotentialPrimitiveType {
- QAnyStringView name;
- QString file;
- };
-
enum class PopulateMode { No, Yes };
static PreProcessResult preProcess(const MetaType &classDef, PopulateMode populateMode);
void addRelatedTypes();
@@ -267,6 +285,7 @@ private:
QList<QString> m_includes;
QList<QAnyStringView> m_referencedTypes;
QList<QAnyStringView> m_primitiveTypes;
+ QList<UsingDeclaration> m_usingDeclarations;
QVector<MetaType> m_types;
QVector<MetaType> m_foreignTypes;
bool m_privateIncludes = false;
diff --git a/src/qmltyperegistrar/qqmltyperegistrar.cpp b/src/qmltyperegistrar/qqmltyperegistrar.cpp
index 058a3180b0..5018bf08b4 100644
--- a/src/qmltyperegistrar/qqmltyperegistrar.cpp
+++ b/src/qmltyperegistrar/qqmltyperegistrar.cpp
@@ -323,18 +323,18 @@ void QmlTypeRegistrar::write(QTextStream &output, QAnyStringView outFileName) co
// We want all related metatypes to be registered by name, so that we can look them up
// without including the C++ headers. That's the reason for the QMetaType(foo).id() calls.
+ const QList<QAnyStringView> namespaces
+ = MetaTypesJsonProcessor::namespaces(classDef);
+
+ const FoundType target = QmlTypesClassDescription::findType(
+ m_types, m_foreignTypes, targetName, namespaces);
+
if (targetIsNamespace) {
// We need to figure out if the _target_ is a namespace. If not, it already has a
// QMetaType and we don't need to generate one.
QString targetTypeName = targetName;
- const QList<QAnyStringView> namespaces
- = MetaTypesJsonProcessor::namespaces(classDef);
-
- const FoundType target = QmlTypesClassDescription::findType(
- m_types, m_foreignTypes, targetName, namespaces);
-
if (!target.javaScript.isEmpty() && target.native.isEmpty())
warning(target.javaScript) << "JavaScript type cannot be used as namespace";
@@ -446,11 +446,27 @@ void QmlTypeRegistrar::write(QTextStream &output, QAnyStringView outFileName) co
}
} else {
Q_ASSERT(!className.isEmpty());
+
+ // Since we don't have a QML name for this type, it can't refer to another type.
+ Q_ASSERT(className == targetName);
+
output << uR"(
QMetaType::fromType<%1%2>().id();)"_s.arg(
className, classDef.kind() == MetaType::Kind::Object ? u" *" : u"");
}
}
+
+ const auto enums = target.native.enums();
+ for (const auto &enumerator : enums) {
+ output << uR"(
+ QMetaType::fromType<%1::%2>().id();)"_s.arg(
+ targetName, enumerator.name.toString());
+ if (!enumerator.alias.isEmpty()) {
+ output << uR"(
+ QMetaType::fromType<%1::%2>().id();)"_s.arg(
+ targetName, enumerator.alias.toString());
+ }
+ }
}
for (const auto [qmlName, exportsForSameQmlName] : qmlElementInfos.asKeyValueRange()) {
@@ -504,6 +520,7 @@ bool QmlTypeRegistrar::generatePluginTypes(const QString &pluginTypesFile)
creator.setOwnTypes(m_types);
creator.setForeignTypes(m_foreignTypes);
creator.setReferencedTypes(m_referencedTypes);
+ creator.setUsingDeclarations(m_usingDeclarations);
creator.setModule(m_module.toUtf8());
creator.setVersion(QTypeRevision::fromVersion(m_moduleVersion.majorVersion(), 0));
@@ -539,4 +556,9 @@ void QmlTypeRegistrar::setReferencedTypes(const QList<QAnyStringView> &reference
m_referencedTypes = referencedTypes;
}
+void QmlTypeRegistrar::setUsingDeclarations(const QList<UsingDeclaration> &usingDeclarations)
+{
+ m_usingDeclarations = usingDeclarations;
+}
+
QT_END_NAMESPACE
diff --git a/src/qmltyperegistrar/qqmltyperegistrar_p.h b/src/qmltyperegistrar/qqmltyperegistrar_p.h
index e0811f2ade..fdfbe15ab7 100644
--- a/src/qmltyperegistrar/qqmltyperegistrar_p.h
+++ b/src/qmltyperegistrar/qqmltyperegistrar_p.h
@@ -35,6 +35,7 @@ class QmlTypeRegistrar
QVector<MetaType> m_types;
QVector<MetaType> m_foreignTypes;
QList<QAnyStringView> m_referencedTypes;
+ QList<UsingDeclaration> m_usingDeclarations;
MetaType findType(QAnyStringView name) const;
MetaType findTypeForeign(QAnyStringView name) const;
@@ -48,6 +49,7 @@ public:
void setIncludes(const QList<QString> &includes);
void setTypes(const QVector<MetaType> &types, const QVector<MetaType> &foreignTypes);
void setReferencedTypes(const QList<QAnyStringView> &referencedTypes);
+ void setUsingDeclarations(const QList<UsingDeclaration> &usingDeclarations);
static bool argumentsFromCommandLineAndFile(QStringList &allArguments,
const QStringList &arguments);
diff --git a/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h b/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h
index 465cc23532..47e3d14cfa 100644
--- a/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h
+++ b/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h
@@ -163,6 +163,7 @@ static constexpr QLatin1StringView S_ROOT { "QML.Root" }
static constexpr QLatin1StringView S_SEQUENCE { "QML.Sequence" };
static constexpr QLatin1StringView S_SINGLETON { "QML.Singleton" };
static constexpr QLatin1StringView S_UNCREATABLE_REASON { "QML.UncreatableReason" };
+static constexpr QLatin1StringView S_USING { "QML.Using" };
} // namespace Qml
} // namespace MetatypesJson
diff --git a/src/qmltyperegistrar/qqmltypesclassdescription.cpp b/src/qmltyperegistrar/qqmltypesclassdescription.cpp
index 7c42052a70..bbb1b25f9b 100644
--- a/src/qmltyperegistrar/qqmltypesclassdescription.cpp
+++ b/src/qmltyperegistrar/qqmltypesclassdescription.cpp
@@ -457,48 +457,99 @@ FoundType QmlTypesClassDescription::collectRelated(
return FoundType();
}
+struct UsingCompare {
+ bool operator()(const UsingDeclaration &a, QAnyStringView b) const
+ {
+ return a.alias < b;
+ }
-ResolvedTypeAlias::ResolvedTypeAlias(QAnyStringView alias)
+ bool operator()(QAnyStringView a, const UsingDeclaration &b) const
+ {
+ return a < b.alias;
+ }
+};
+
+ResolvedTypeAlias::ResolvedTypeAlias(
+ QAnyStringView alias, const QList<UsingDeclaration> &usingDeclarations)
: type(alias)
{
+ handleVoid();
if (type.isEmpty())
return;
- if (type == "void") {
- type = "";
- return;
+ handleList();
+
+ if (!isList) {
+ handlePointer();
+ handleConst();
+ }
+
+ while (true) {
+ const auto usingDeclaration = std::equal_range(
+ usingDeclarations.begin(), usingDeclarations.end(), type, UsingCompare());
+ if (usingDeclaration.first == usingDeclaration.second)
+ break;
+
+ type = usingDeclaration.first->original;
+ handleVoid();
+ if (type.isEmpty())
+ return;
+
+ if (isPointer) {
+ handleConst();
+ continue;
+ }
+
+ if (!isList) {
+ handleList();
+ if (!isList) {
+ handlePointer();
+ handleConst();
+ }
+ }
}
+}
- // This is a best effort approach and will not return correct results in the
- // presence of typedefs.
+void ResolvedTypeAlias::handleVoid()
+{
+ if (type == "void")
+ type = "";
+}
- auto handleList = [&](QLatin1StringView list) {
+void ResolvedTypeAlias::handleList()
+{
+ for (QLatin1StringView list : {"QQmlListProperty<"_L1, "QList<"_L1}) {
if (!startsWith(type, list) || type.back() != '>'_L1)
- return false;
+ continue;
const int listSize = list.size();
const QAnyStringView elementType = trimmed(type.mid(listSize, type.size() - listSize - 1));
- // QQmlListProperty internally constructs the pointer. Passing an explicit '*' will
- // produce double pointers. QList is only for value types. We can't handle QLists
- // of pointers (unless specially registered, but then they're not isList).
+ // QQmlListProperty internally constructs the pointer. Passing an explicit '*' will
+ // produce double pointers. QList is only for value types. We can't handle QLists
+ // of pointers (unless specially registered, but then they're not isList).
if (elementType.back() == '*'_L1)
- return false;
+ continue;
isList = true;
type = elementType;
- return true;
- };
+ return;
+ }
+}
- if (!handleList("QQmlListProperty<"_L1) && !handleList("QList<"_L1)) {
- if (type.back() == '*'_L1) {
- isPointer = true;
- type = type.chopped(1);
- }
- if (startsWith(type, "const "_L1)) {
- isConstant = true;
- type = type.sliced(strlen("const "));
- }
+void ResolvedTypeAlias::handlePointer()
+{
+ if (type.back() == '*'_L1) {
+ isPointer = true;
+ type = type.chopped(1);
+ }
+}
+
+void ResolvedTypeAlias::handleConst()
+{
+ if (startsWith(type, "const "_L1)) {
+ isConstant = true;
+ type = type.sliced(strlen("const "));
}
}
diff --git a/src/qmltyperegistrar/qqmltypesclassdescription_p.h b/src/qmltyperegistrar/qqmltypesclassdescription_p.h
index 60aafb948f..b48a0670da 100644
--- a/src/qmltyperegistrar/qqmltypesclassdescription_p.h
+++ b/src/qmltyperegistrar/qqmltypesclassdescription_p.h
@@ -113,12 +113,18 @@ private:
struct ResolvedTypeAlias
{
- ResolvedTypeAlias(QAnyStringView alias);
+ ResolvedTypeAlias(QAnyStringView alias, const QList<UsingDeclaration> &usingDeclarations);
QAnyStringView type;
bool isList = false;
bool isPointer = false;
bool isConstant = false;
+
+private:
+ void handleVoid();
+ void handleList();
+ void handlePointer();
+ void handleConst();
};
QT_END_NAMESPACE
diff --git a/src/qmltyperegistrar/qqmltypescreator.cpp b/src/qmltyperegistrar/qqmltypescreator.cpp
index 297a23679a..1852bf7af8 100644
--- a/src/qmltyperegistrar/qqmltypescreator.cpp
+++ b/src/qmltyperegistrar/qqmltypescreator.cpp
@@ -144,7 +144,9 @@ void QmlTypesCreator::writeClassProperties(const QmlTypesClassDescription &colle
exportStrings.append(QUtf8StringView(entry));
m_qml.writeStringListBinding(S_EXPORTS, exportStrings);
- m_qml.writeBooleanBinding(S_IS_CREATABLE, collector.isCreatable && !collector.isSingleton);
+
+ if (!collector.isCreatable || collector.isSingleton)
+ m_qml.writeBooleanBinding(S_IS_CREATABLE, false);
if (collector.isStructured)
m_qml.writeBooleanBinding(S_IS_STRUCTURED, true);
@@ -163,7 +165,7 @@ void QmlTypesCreator::writeClassProperties(const QmlTypesClassDescription &colle
void QmlTypesCreator::writeType(QAnyStringView type)
{
- ResolvedTypeAlias resolved(type);
+ ResolvedTypeAlias resolved(type, m_usingDeclarations);
if (resolved.type.isEmpty())
return;
diff --git a/src/qmltyperegistrar/qqmltypescreator_p.h b/src/qmltyperegistrar/qqmltypescreator_p.h
index 10c5a3d35d..c30c00c889 100644
--- a/src/qmltyperegistrar/qqmltypescreator_p.h
+++ b/src/qmltyperegistrar/qqmltypescreator_p.h
@@ -35,6 +35,7 @@ public:
void setReferencedTypes(QList<QAnyStringView> referencedTypes) { m_referencedTypes = std::move(referencedTypes); }
void setModule(QByteArray module) { m_module = std::move(module); }
void setVersion(QTypeRevision version) { m_version = version; }
+ void setUsingDeclarations(QList<UsingDeclaration> usingDeclarations) { m_usingDeclarations = std::move(usingDeclarations);}
private:
void writeComponent(const QmlTypesClassDescription &collector);
@@ -54,6 +55,7 @@ private:
QVector<MetaType> m_ownTypes;
QVector<MetaType> m_foreignTypes;
QList<QAnyStringView> m_referencedTypes;
+ QList<UsingDeclaration> m_usingDeclarations;
QByteArray m_module;
QTypeRevision m_version = QTypeRevision::zero();
};
diff --git a/src/qmlworkerscript/CMakeLists.txt b/src/qmlworkerscript/CMakeLists.txt
index 1704d5ae16..93e97834b6 100644
--- a/src/qmlworkerscript/CMakeLists.txt
+++ b/src/qmlworkerscript/CMakeLists.txt
@@ -12,7 +12,7 @@ qt_internal_add_qml_module(QmlWorkerScript
PLUGIN_TARGET workerscriptplugin
CLASS_NAME QtQmlWorkerScriptPlugin
DEPENDENCIES
- QtQml.Base/auto
+ QML/1.0
SOURCES
qquickworkerscript.cpp qquickworkerscript_p.h
qtqmlworkerscriptglobal.h qtqmlworkerscriptglobal_p.h
diff --git a/src/quick/CMakeLists.txt b/src/quick/CMakeLists.txt
index 86edb893c2..d422d7e20b 100644
--- a/src/quick/CMakeLists.txt
+++ b/src/quick/CMakeLists.txt
@@ -181,7 +181,7 @@ qt_internal_add_qml_module(Quick
scenegraph/util/qsgvertexcolormaterial.cpp scenegraph/util/qsgvertexcolormaterial.h
scenegraph/util/qquadpath.cpp scenegraph/util/qquadpath_p.h
scenegraph/util/qsggradientcache.cpp scenegraph/util/qsggradientcache_p.h
- util/qminimalflatset_p.h
+ scenegraph/util/qsgtransform.cpp scenegraph/util/qsgtransform_p.h
util/qquickanimation.cpp util/qquickanimation_p.h
util/qquickanimation_p_p.h
util/qquickanimationcontroller.cpp util/qquickanimationcontroller_p.h
@@ -237,16 +237,19 @@ qt_internal_add_qml_module(Quick
Qt::GuiPrivate
Qt::QmlModelsPrivate
Qt::QmlPrivate
+ Qt::QmlMetaPrivate
PUBLIC_LIBRARIES
Qt::Core
Qt::Gui
Qt::Qml
+ Qt::QmlMeta
Qt::QmlModels
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
Qt::GuiPrivate
Qt::QmlModelsPrivate
Qt::QmlPrivate
+ Qt::QmlMetaPrivate
GENERATE_CPP_EXPORTS
)
@@ -464,6 +467,43 @@ qt_internal_add_shaders(Quick "scenegraph_curve_shaders_cg_derivatives"
"scenegraph/shaders_ng/shapecurve_cg_derivatives.vert.qsb"
)
+qt_internal_add_shaders(Quick "scenegraph_curve_shaders_tf"
+ SILENT
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
+ MULTIVIEW
+ DEFINES
+ "TEXTUREFILL"
+ PREFIX
+ "/qt-project.org"
+ FILES
+ "scenegraph/shaders_ng/shapecurve.frag"
+ "scenegraph/shaders_ng/shapecurve.vert"
+ OUTPUTS
+ "scenegraph/shaders_ng/shapecurve_tf.frag.qsb"
+ "scenegraph/shaders_ng/shapecurve_tf.vert.qsb"
+)
+
+qt_internal_add_shaders(Quick "scenegraph_curve_shaders_tf_derivatives"
+ SILENT
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
+ MULTIVIEW
+ DEFINES
+ "TEXTUREFILL"
+ "USE_DERIVATIVES"
+ PREFIX
+ "/qt-project.org"
+ FILES
+ "scenegraph/shaders_ng/shapecurve.frag"
+ "scenegraph/shaders_ng/shapecurve.vert"
+ OUTPUTS
+ "scenegraph/shaders_ng/shapecurve_tf_derivatives.frag.qsb"
+ "scenegraph/shaders_ng/shapecurve_tf_derivatives.vert.qsb"
+)
+
qt_internal_extend_target(Quick CONDITION QT_FEATURE_qml_network
LIBRARIES
Qt::Network
@@ -562,6 +602,11 @@ qt_internal_extend_target(Quick CONDITION QT_FEATURE_metal
qt_internal_extend_target(Quick CONDITION ANDROID
SOURCES
platform/android/qandroidquickviewembedding.cpp platform/android/qandroidquickviewembedding_p.h
+ platform/android/qandroidviewsignalmanager.cpp platform/android/qandroidviewsignalmanager_p.h
+ platform/android/qandroiditemmodelproxy.cpp platform/android/qandroiditemmodelproxy_p.h
+ platform/android/qandroidmodelindexproxy.cpp platform/android/qandroidmodelindexproxy_p.h
+ platform/android/qandroidtypes_p.h
+ platform/android/qandroidtypeconverter_p.h
)
if (ANDROID)
add_subdirectory(jar)
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
index 514b1a9214..5824b63a4c 100644
--- a/src/quick/accessible/qaccessiblequickitem.cpp
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
@@ -604,6 +604,20 @@ QString QAccessibleQuickItem::text(QAccessible::Text textType) const
if (!accessibleDecription.isNull())
return accessibleDecription.toString();
break;}
+ case QAccessible::Identifier: {
+ QVariant accessibleIdentifier = QQuickAccessibleAttached::property(object(), "id");
+ if (!accessibleIdentifier.isNull())
+ return accessibleIdentifier.toString();
+ auto quickItem = item();
+ if (quickItem->isComponentComplete()) {
+ QQmlContext *context = qmlContext(quickItem);
+ if (context) {
+ const auto objectId = context->nameForObject(quickItem);
+ if (!objectId.isEmpty())
+ return objectId;
+ }
+ }
+ break;}
#ifdef Q_ACCESSIBLE_QUICK_ITEM_ENABLE_DEBUG_DESCRIPTION
case QAccessible::DebugDescription: {
QString debugString;
@@ -709,19 +723,20 @@ QRect itemScreenRect(QQuickItem *item)
return QRect();
}
- QSize itemSize((int)item->width(), (int)item->height());
+ QSizeF itemSize(item->width(), item->height());
// ### If the bounding rect fails, we first try the implicit size, then we go for the
// parent size. WE MIGHT HAVE TO REVISIT THESE FALLBACKS.
if (itemSize.isEmpty()) {
- itemSize = QSize((int)item->implicitWidth(), (int)item->implicitHeight());
+ itemSize = QSize(item->implicitWidth(), item->implicitHeight());
if (itemSize.isEmpty() && item->parentItem())
// ### Seems that the above fallback is not enough, fallback to use the parent size...
- itemSize = QSize((int)item->parentItem()->width(), (int)item->parentItem()->height());
+ itemSize = QSize(item->parentItem()->width(), item->parentItem()->height());
}
- QPointF scenePoint = item->mapToScene(QPointF(0, 0));
- QPoint screenPos = item->window()->mapToGlobal(scenePoint.toPoint());
- return QRect(screenPos, itemSize);
+ QRectF sceneRect = item->mapRectToScene(QRectF(QPointF(0, 0), itemSize));
+ QPoint screenPos = item->window()->mapToGlobal(sceneRect.topLeft().toPoint());
+ QSize screenSize = sceneRect.size().toSize();
+ return QRect(screenPos, screenSize);
}
QTextDocument *QAccessibleQuickItem::textDocument() const
diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf
index 913d4408c2..deda199b96 100644
--- a/src/quick/doc/qtquick.qdocconf
+++ b/src/quick/doc/qtquick.qdocconf
@@ -97,7 +97,8 @@ imagedirs += images
excludefiles += ../util/qquickpropertychanges_p.h
examples.fileextensions += "*.qm" \
- "*.java"
+ "*.java" \
+ "*.kt"
manifestmeta.thumbnail.names += "QtQuick/QML Dynamic View Ordering Tutorial*"
diff --git a/src/quick/doc/snippets/qml/font.qml b/src/quick/doc/snippets/qml/font.qml
new file mode 100644
index 0000000000..5f76d6fc30
--- /dev/null
+++ b/src/quick/doc/snippets/qml/font.qml
@@ -0,0 +1,22 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+Item {
+//! [text]
+ Text {
+ font.family: "Helvetica"
+ font.pointSize: 13
+ font.bold: true
+ }
+//! [text]
+
+//! [structured-value-construction]
+ readonly property font myFont: ({
+ family: "Helvetica",
+ pointSize: 13,
+ bold: true
+ })
+//! [structured-value-construction]
+}
diff --git a/src/quick/doc/snippets/qml/windowPalette.qml b/src/quick/doc/snippets/qml/windowPalette.qml
index 0638213c57..5a9219c638 100644
--- a/src/quick/doc/snippets/qml/windowPalette.qml
+++ b/src/quick/doc/snippets/qml/windowPalette.qml
@@ -17,12 +17,14 @@ Window {
palette.active.window: "peachpuff"
palette.windowText: "brown"
+//![text-item]
Text {
anchors.centerIn: parent
// here we use the Window.active attached property and the Item.palette property
color: Window.active ? palette.active.windowText : palette.inactive.windowText
text: Window.active ? "active" : "inactive"
}
+//![text-item]
Button {
text: "Button"
diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc
index e1ebca8106..215c338db2 100644
--- a/src/quick/doc/src/qmltypereference.qdoc
+++ b/src/quick/doc/src/qmltypereference.qdoc
@@ -114,7 +114,7 @@ available when you import \c QtQuick.
\section1 SVG Color Reference
The following table lists the available
- \l {http://www.w3.org/TR/SVG/types.html#ColorKeywords}{SVG colors}:
+ \l {https://www.w3.org/TR/css-color-3/#svg-color}{SVG colors}:
\include svg-colors.qdocinc
@@ -160,12 +160,18 @@ available when you import \c QtQuick.
\li \c object \l [QML] {QtQuick::Text::}{font.features}
\li \l string \c font.styleName
\li \c object \c [QML] {QtQuick::Text::}{font.variableAxes}
+ \li \l bool \c font.contextFontMerging
+ \li \l bool \c font.preferTypoLineMetrics
\endlist
Example:
- \qml
- Text { font.family: "Helvetica"; font.pointSize: 13; font.bold: true }
- \endqml
+
+ \snippet qml/font.qml text
+
+ As \c font is a \l {QML_STRUCTURED_VALUE}{structured value} type, it can
+ also be constructed with a JavaScript object:
+
+ \snippet qml/font.qml structured-value-construction
When integrating with C++, note that any QFont value
\l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
diff --git a/src/quick/doc/src/qtquick.qdoc b/src/quick/doc/src/qtquick.qdoc
index 31dd680d93..0d0890398f 100644
--- a/src/quick/doc/src/qtquick.qdoc
+++ b/src/quick/doc/src/qtquick.qdoc
@@ -143,6 +143,13 @@ To find out more about using the QML language, see the \l{Qt Qml} module documen
- provides classes for using QML with Java/Kotlin Android APIs.
\endlist
+\section1 Qt Academy Courses
+ \list
+ \li \l {https://www.qt.io/academy/course-catalog#introduction-to-qt-quick}
+ {Introduction to Qt Quick}
+ \endlist
+
+
\section1 Licenses and Attributions
Qt Quick is available under commercial licenses from \l{The Qt Company}.
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index 865fb8bf11..bd24d1b1de 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -120,6 +120,15 @@ QT_BEGIN_NAMESPACE
\endtable
*/
+/*!
+ \qmlproperty string QtQuick::Accessible::id
+
+ This property sets an identifier for the object.
+ It can be used to provide stable identifiers to UI tests.
+ By default, the identifier is set to the ID of the QML object.
+ If the ID is not set the default of \l QAccessible::Identifier is used.
+*/
+
/*! \qmlproperty bool QtQuick::Accessible::focusable
\brief This property holds whether this item is focusable.
@@ -301,15 +310,19 @@ QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
: QObject(parent), m_role(QAccessible::NoRole)
{
Q_ASSERT(parent);
- if (!item()) {
- qmlWarning(parent) << "Accessible must be attached to an Item";
- return;
- }
-
// Enable accessibility for items with accessible content. This also
- // enables accessibility for the ancestors of souch items.
- item()->d_func()->setAccessible();
- QAccessibleEvent ev(item(), QAccessible::ObjectCreated);
+ // enables accessibility for the ancestors of such items.
+ auto item = qobject_cast<QQuickItem *>(parent);
+ if (item) {
+ item->d_func()->setAccessible();
+ } else {
+ const QLatin1StringView className(QQmlData::ensurePropertyCache(parent)->firstCppMetaObject()->className());
+ if (className != QLatin1StringView("QQuickAction")) {
+ qmlWarning(parent) << "Accessible must be attached to an Item or an Action";
+ return;
+ }
+ }
+ QAccessibleEvent ev(parent, QAccessible::ObjectCreated);
QAccessible::updateAccessibility(&ev);
if (const QMetaObject *pmo = parent->metaObject()) {
@@ -423,13 +436,15 @@ QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObjec
bool QQuickAccessibleAttached::ignored() const
{
- return item() ? !item()->d_func()->isAccessible : false;
+ auto item = qobject_cast<QQuickItem *>(parent());
+ return item ? !item->d_func()->isAccessible : false;
}
void QQuickAccessibleAttached::setIgnored(bool ignored)
{
- if (this->ignored() != ignored && item()) {
- item()->d_func()->isAccessible = !ignored;
+ auto item = qobject_cast<QQuickItem *>(parent());
+ if (item && this->ignored() != ignored) {
+ item->d_func()->isAccessible = !ignored;
emit ignoredChanged();
}
}
@@ -457,8 +472,13 @@ bool QQuickAccessibleAttached::doAction(const QString &actionName)
sig = &sigPreviousPage;
else if (actionName == QAccessibleActionInterface::nextPageAction())
sig = &sigNextPage;
- if (sig && isSignalConnected(*sig))
- return sig->invoke(this);
+ if (sig && isSignalConnected(*sig)) {
+ bool ret = false;
+ if (m_proxying)
+ ret = sig->invoke(m_proxying);
+ ret |= sig->invoke(this);
+ return ret;
+ }
return false;
}
@@ -497,6 +517,69 @@ QString QQuickAccessibleAttached::stripHtml(const QString &html)
#endif
}
+void QQuickAccessibleAttached::setProxying(QQuickAccessibleAttached *proxying)
+{
+ if (proxying == m_proxying)
+ return;
+
+ const QMetaObject &mo = staticMetaObject;
+ if (m_proxying) {
+ // We disconnect all signals from the proxy into this object
+ auto mo = m_proxying->metaObject();
+ auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
+ for (int signalIndex = propertyCache->signalOffset();
+ signalIndex < propertyCache->signalCount(); ++signalIndex) {
+ const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
+ Q_ASSERT(m.methodType() == QMetaMethod::Signal);
+ if (m.methodType() != QMetaMethod::Signal)
+ continue;
+
+ disconnect(m_proxying, m, this, m);
+ }
+ }
+
+ m_proxying = proxying;
+
+ if (m_proxying) {
+ // We connect all signals from the proxy into this object
+ auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
+ auto mo = m_proxying->metaObject();
+ for (int signalIndex = propertyCache->signalOffset();
+ signalIndex < propertyCache->signalCount(); ++signalIndex) {
+ const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
+ Q_ASSERT(m.methodType() == QMetaMethod::Signal);
+ connect(proxying, m, this, m);
+ }
+ }
+
+ // We check all properties
+ for (int prop = mo.propertyOffset(); prop < mo.propertyCount(); ++prop) {
+ const QMetaProperty p = mo.property(prop);
+ if (!p.hasNotifySignal()) {
+ continue;
+ }
+
+ const QMetaMethod signal = p.notifySignal();
+ if (signal.parameterCount() == 0)
+ signal.invoke(this);
+ else
+ signal.invoke(this, Q_ARG(bool, p.read(this).toBool()));
+ }
+}
+
+/*!
+ * \since 6.8
+ * Issues an announcement event with a \a message with priority \a priority.
+ *
+ * \sa QAccessibleAnnouncementEvent
+ */
+void QQuickAccessibleAttached::announce(const QString &message, QAccessible::AnnouncementPriority priority)
+{
+ QAccessibleAnnouncementEvent event(parent(), message);
+ event.setPriority(priority);
+ QAccessible::updateAccessibility(&event);
+}
+
QT_END_NAMESPACE
#include "moc_qquickaccessibleattached_p.cpp"
diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h
index 92d1307a9a..3ec8fcab98 100644
--- a/src/quick/items/qquickaccessibleattached_p.h
+++ b/src/quick/items/qquickaccessibleattached_p.h
@@ -30,9 +30,11 @@ QT_BEGIN_NAMESPACE
#define STATE_PROPERTY(P) \
Q_PROPERTY(bool P READ P WRITE set_ ## P NOTIFY P ## Changed FINAL) \
- bool P() const { return m_state.P ; } \
+ bool P() const { return m_proxying && !m_stateExplicitlySet.P ? m_proxying->P() : m_state.P ; } \
void set_ ## P(bool arg) \
{ \
+ if (m_proxying) \
+ m_proxying->set_##P(arg);\
m_stateExplicitlySet.P = true; \
if (m_state.P == arg) \
return; \
@@ -51,6 +53,7 @@ class Q_QUICK_EXPORT QQuickAccessibleAttached : public QObject
Q_PROPERTY(QAccessible::Role role READ role WRITE setRole NOTIFY roleChanged FINAL)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL)
Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged FINAL)
+ Q_PROPERTY(QString id READ id WRITE setId NOTIFY idChanged REVISION(6, 8) FINAL)
Q_PROPERTY(bool ignored READ ignored WRITE setIgnored NOTIFY ignoredChanged FINAL)
QML_NAMED_ELEMENT(Accessible)
@@ -84,6 +87,8 @@ public:
QString name() const {
if (m_state.passwordEdit)
return QString();
+ if (m_proxying)
+ return m_proxying->name();
return m_name;
}
@@ -99,9 +104,15 @@ public:
}
void setNameImplicitly(const QString &name);
- QString description() const { return m_description; }
+ QString description() const {
+ return !m_descriptionExplicitlySet && m_proxying ? m_proxying->description() : m_description;
+ }
void setDescription(const QString &description)
{
+ if (!m_descriptionExplicitlySet && m_proxying) {
+ disconnect(m_proxying, &QQuickAccessibleAttached::descriptionChanged, this, &QQuickAccessibleAttached::descriptionChanged);
+ }
+ m_descriptionExplicitlySet = true;
if (m_description != description) {
m_description = description;
Q_EMIT descriptionChanged();
@@ -110,6 +121,17 @@ public:
}
}
+ QString id() const { return m_id; }
+ void setId(const QString &id)
+ {
+ if (m_id != id) {
+ m_id = id;
+ Q_EMIT idChanged();
+ QAccessibleEvent ev(parent(), QAccessible::IdentifierChanged);
+ QAccessible::updateAccessibility(&ev);
+ }
+ }
+
// Factory function
static QQuickAccessibleAttached *qmlAttachedProperties(QObject *obj);
@@ -143,6 +165,13 @@ public:
if (att && (role == QAccessible::NoRole || att->role() == role)) {
break;
}
+ if (auto action = object->property("action").value<QObject *>(); action) {
+ QQuickAccessibleAttached *att = QQuickAccessibleAttached::attachedProperties(action);
+ if (att && (role == QAccessible::NoRole || att->role() == role)) {
+ object = action;
+ break;
+ }
+ }
object = object->parent();
}
return object;
@@ -154,6 +183,9 @@ public:
void availableActions(QStringList *actions) const;
Q_REVISION(6, 2) Q_INVOKABLE static QString stripHtml(const QString &html);
+ void setProxying(QQuickAccessibleAttached *proxying);
+
+ Q_REVISION(6, 8) Q_INVOKABLE void announce(const QString &message, QAccessible::AnnouncementPriority priority = QAccessible::AnnouncementPriority::Polite);
public Q_SLOTS:
void valueChanged() {
@@ -171,6 +203,7 @@ Q_SIGNALS:
void roleChanged();
void nameChanged();
void descriptionChanged();
+ void idChanged();
void ignoredChanged();
void pressAction();
void toggleAction();
@@ -184,14 +217,15 @@ Q_SIGNALS:
void nextPageAction();
private:
- QQuickItem *item() const { return qobject_cast<QQuickItem*>(parent()); }
-
QAccessible::Role m_role;
QAccessible::State m_state;
QAccessible::State m_stateExplicitlySet;
QString m_name;
bool m_nameExplicitlySet = false;
QString m_description;
+ bool m_descriptionExplicitlySet = false;
+ QQuickAccessibleAttached* m_proxying = nullptr;
+ QString m_id;
static QMetaMethod sigPress;
static QMetaMethod sigToggle;
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index 40daf518d3..004f0491bd 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -400,11 +400,16 @@ void QQuickBorderImage::requestFinished()
{
Q_D(QQuickBorderImage);
- const QSize impsize = d->pix.implicitSize();
+ if (d->pendingPix != d->currentPix) {
+ std::swap(d->pendingPix, d->currentPix);
+ d->pendingPix->clear(this); // Clear the old image
+ }
+
+ const QSize impsize = d->currentPix->implicitSize();
setImplicitSize(impsize.width() / d->devicePixelRatio, impsize.height() / d->devicePixelRatio);
- if (d->pix.isError()) {
- qmlWarning(this) << d->pix.error();
+ if (d->currentPix->isError()) {
+ qmlWarning(this) << d->currentPix->error();
d->setStatus(Error);
d->setProgress(0);
} else {
@@ -416,8 +421,8 @@ void QQuickBorderImage::requestFinished()
d->oldSourceSize = sourceSize();
emit sourceSizeChanged();
}
- if (d->frameCount != d->pix.frameCount()) {
- d->frameCount = d->pix.frameCount();
+ if (d->frameCount != d->currentPix->frameCount()) {
+ d->frameCount = d->currentPix->frameCount();
emit frameCountChanged();
}
@@ -507,7 +512,7 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
{
Q_D(QQuickBorderImage);
- QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window());
+ QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->currentPix->textureFactory(), window());
if (!texture || width() <= 0 || height() <= 0) {
delete oldNode;
@@ -532,7 +537,7 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
QRectF innerSourceRect;
QRectF subSourceRect;
d->calculateRects(d->border,
- QSize(d->pix.width(), d->pix.height()), QSizeF(width(), height()),
+ QSize(d->currentPix->width(), d->currentPix->height()), QSizeF(width(), height()),
d->horizontalTileMode, d->verticalTileMode, d->devicePixelRatio,
&targetRect, &innerTargetRect,
&innerSourceRect, &subSourceRect);
@@ -577,6 +582,13 @@ void QQuickBorderImage::pixmapChange()
frameCount is the number of frames in the image. Most images have only one frame.
*/
+/*!
+ \qmlproperty bool QtQuick::BorderImage::retainWhileLoading
+ \since 6.8
+
+ \include qquickimage.cpp qml-image-retainwhileloading
+ */
+
QT_END_NAMESPACE
#include "moc_qquickborderimage_p.cpp"
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index dbe443b2b3..47064ad433 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -362,7 +362,7 @@ void QQuickDragAttached::setImageSource(const QUrl &url)
}
/*!
- \qmlattachedproperty QUrl QtQuick::Drag::imageSourceSize
+ \qmlattachedproperty size QtQuick::Drag::imageSourceSize
\since 6.8
This property holds the size of the image that will be used to represent
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 3aaa59819c..3efe082332 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -218,7 +218,7 @@ QQuickImage::~QQuickImage()
void QQuickImagePrivate::setImage(const QImage &image)
{
Q_Q(QQuickImage);
- pix.setImage(image);
+ currentPix->setImage(image);
q->pixmapChange();
q->update();
}
@@ -226,7 +226,7 @@ void QQuickImagePrivate::setImage(const QImage &image)
void QQuickImagePrivate::setPixmap(const QQuickPixmap &pixmap)
{
Q_Q(QQuickImage);
- pix.setPixmap(pixmap);
+ currentPix->setPixmap(pixmap);
q->pixmapChange();
q->update();
}
@@ -605,12 +605,12 @@ void QQuickImage::updatePaintedGeometry()
Q_D(QQuickImage);
if (d->fillMode == PreserveAspectFit) {
- if (!d->pix.width() || !d->pix.height()) {
+ if (!d->currentPix->width() || !d->currentPix->height()) {
setImplicitSize(0, 0);
return;
}
- const qreal pixWidth = d->pix.width() / d->devicePixelRatio;
- const qreal pixHeight = d->pix.height() / d->devicePixelRatio;
+ const qreal pixWidth = d->currentPix->width() / d->devicePixelRatio;
+ const qreal pixHeight = d->currentPix->height() / d->devicePixelRatio;
const qreal w = widthValid() ? width() : pixWidth;
const qreal widthScale = w / pixWidth;
const qreal h = heightValid() ? height() : pixHeight;
@@ -627,10 +627,10 @@ void QQuickImage::updatePaintedGeometry()
setImplicitSize(iWidth, iHeight);
} else if (d->fillMode == PreserveAspectCrop) {
- if (!d->pix.width() || !d->pix.height())
+ if (!d->currentPix->width() || !d->currentPix->height())
return;
- const qreal pixWidth = d->pix.width() / d->devicePixelRatio;
- const qreal pixHeight = d->pix.height() / d->devicePixelRatio;
+ const qreal pixWidth = d->currentPix->width() / d->devicePixelRatio;
+ const qreal pixHeight = d->currentPix->height() / d->devicePixelRatio;
qreal widthScale = width() / pixWidth;
qreal heightScale = height() / pixHeight;
if (widthScale < heightScale) {
@@ -642,8 +642,8 @@ void QQuickImage::updatePaintedGeometry()
d->paintedHeight = heightScale * pixHeight;
d->paintedWidth = widthScale * pixWidth;
} else if (d->fillMode == Pad) {
- d->paintedWidth = d->pix.width() / d->devicePixelRatio;
- d->paintedHeight = d->pix.height() / d->devicePixelRatio;
+ d->paintedWidth = d->currentPix->width() / d->devicePixelRatio;
+ d->paintedHeight = d->currentPix->height() / d->devicePixelRatio;
} else {
d->paintedWidth = width();
d->paintedHeight = height();
@@ -685,7 +685,7 @@ QSGTextureProvider *QQuickImage::textureProvider() const
dd->provider = new QQuickImageTextureProvider;
dd->provider->m_smooth = d->smooth;
dd->provider->m_mipmap = d->mipmap;
- dd->provider->updateTexture(d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window()));
+ dd->provider->updateTexture(d->sceneGraphRenderContext()->textureForFactory(d->currentPix->textureFactory(), window()));
}
return d->provider;
@@ -711,7 +711,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
Q_D(QQuickImage);
- QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window());
+ QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->currentPix->textureFactory(), window());
// Copy over the current texture state into the texture provider...
if (d->provider) {
@@ -736,8 +736,8 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
QSGTexture::WrapMode hWrap = QSGTexture::ClampToEdge;
QSGTexture::WrapMode vWrap = QSGTexture::ClampToEdge;
- qreal pixWidth = (d->fillMode == PreserveAspectFit) ? d->paintedWidth : d->pix.width() / d->devicePixelRatio;
- qreal pixHeight = (d->fillMode == PreserveAspectFit) ? d->paintedHeight : d->pix.height() / d->devicePixelRatio;
+ qreal pixWidth = (d->fillMode == PreserveAspectFit) ? d->paintedWidth : d->currentPix->width() / d->devicePixelRatio;
+ qreal pixHeight = (d->fillMode == PreserveAspectFit) ? d->paintedHeight : d->currentPix->height() / d->devicePixelRatio;
int xOffset = 0;
if (d->hAlign == QQuickImage::AlignHCenter)
@@ -754,36 +754,36 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
switch (d->fillMode) {
case Stretch:
targetRect = QRectF(0, 0, width(), height());
- sourceRect = d->pix.rect();
+ sourceRect = d->currentPix->rect();
break;
case PreserveAspectFit:
targetRect = QRectF(xOffset, yOffset, d->paintedWidth, d->paintedHeight);
- sourceRect = d->pix.rect();
+ sourceRect = d->currentPix->rect();
break;
case PreserveAspectCrop: {
targetRect = QRectF(0, 0, width(), height());
- qreal wscale = width() / qreal(d->pix.width());
- qreal hscale = height() / qreal(d->pix.height());
+ qreal wscale = width() / qreal(d->currentPix->width());
+ qreal hscale = height() / qreal(d->currentPix->height());
if (wscale > hscale) {
- int src = (hscale / wscale) * qreal(d->pix.height());
+ int src = (hscale / wscale) * qreal(d->currentPix->height());
int y = 0;
if (d->vAlign == QQuickImage::AlignVCenter)
- y = qCeil((d->pix.height() - src) / 2.);
+ y = qCeil((d->currentPix->height() - src) / 2.);
else if (d->vAlign == QQuickImage::AlignBottom)
- y = qCeil(d->pix.height() - src);
- sourceRect = QRectF(0, y, d->pix.width(), src);
+ y = qCeil(d->currentPix->height() - src);
+ sourceRect = QRectF(0, y, d->currentPix->width(), src);
} else {
- int src = (wscale / hscale) * qreal(d->pix.width());
+ int src = (wscale / hscale) * qreal(d->currentPix->width());
int x = 0;
if (d->hAlign == QQuickImage::AlignHCenter)
- x = qCeil((d->pix.width() - src) / 2.);
+ x = qCeil((d->currentPix->width() - src) / 2.);
else if (d->hAlign == QQuickImage::AlignRight)
- x = qCeil(d->pix.width() - src);
- sourceRect = QRectF(x, 0, src, d->pix.height());
+ x = qCeil(d->currentPix->width() - src);
+ sourceRect = QRectF(x, 0, src, d->currentPix->height());
}
}
break;
@@ -797,13 +797,13 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
case TileHorizontally:
targetRect = QRectF(0, 0, width(), height());
- sourceRect = QRectF(-xOffset, 0, width(), d->pix.height());
+ sourceRect = QRectF(-xOffset, 0, width(), d->currentPix->height());
hWrap = QSGTexture::Repeat;
break;
case TileVertically:
targetRect = QRectF(0, 0, width(), height());
- sourceRect = QRectF(0, -yOffset, d->pix.width(), height());
+ sourceRect = QRectF(0, -yOffset, d->currentPix->width(), height());
vWrap = QSGTexture::Repeat;
break;
@@ -817,8 +817,8 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
break;
}
- qreal nsWidth = (hWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.width() / d->devicePixelRatio : d->pix.width();
- qreal nsHeight = (vWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.height() / d->devicePixelRatio : d->pix.height();
+ qreal nsWidth = (hWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->currentPix->width() / d->devicePixelRatio : d->currentPix->width();
+ qreal nsHeight = (vWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->currentPix->height() / d->devicePixelRatio : d->currentPix->height();
QRectF nsrect(sourceRect.x() / nsWidth,
sourceRect.y() / nsHeight,
sourceRect.width() / nsWidth,
@@ -967,6 +967,25 @@ void QQuickImage::setMipmap(bool use)
frameCount is the number of frames in the image. Most images have only one frame.
*/
+/*!
+ \qmlproperty bool QtQuick::Image::retainWhileLoading
+ \since 6.8
+
+//! [qml-image-retainwhileloading]
+ This property defines the behavior when the \l source property is changed and loading happens
+ asynchronously. This is the case when the \l asynchronous property is set to \c true, or if the
+ image is not on the local file system.
+
+ If \c retainWhileLoading is \c false (the default), the old image is discarded immediately, and
+ the component is cleared while the new image is being loaded. If set to \c true, the old image
+ is retained and remains visible until the new one is ready.
+
+ Enabling this property can avoid flickering in cases where loading the new image takes a long
+ time. It comes at the cost of some extra memory use for double buffering while the new image is
+ being loaded.
+//! [qml-image-retainwhileloading]
+ */
+
QT_END_NAMESPACE
#include "moc_qquickimage_p_p.cpp"
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index ab827379fb..b00baf7f7d 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -15,16 +15,7 @@
QT_BEGIN_NAMESPACE
-bool isScalableImageFormat(const QUrl &url)
-{
- if (url.scheme() == QLatin1String("image"))
- return true;
-
- const QString stringUrl = url.path(QUrl::PrettyDecoded);
- return stringUrl.endsWith(QLatin1String("svg"))
- || stringUrl.endsWith(QLatin1String("svgz"))
- || stringUrl.endsWith(QLatin1String("pdf"));
-}
+using namespace Qt::Literals::StringLiterals;
// This function gives derived classes the chance set the devicePixelRatio
// if they're not happy with our implementation of it.
@@ -33,7 +24,7 @@ bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio
// QQuickImageProvider and SVG and PDF can generate a high resolution image when
// sourceSize is set. If sourceSize is not set then the provider default size will
// be used, as usual.
- const bool setDevicePixelRatio = isScalableImageFormat(url);
+ const bool setDevicePixelRatio = QQuickPixmap::isScalableImageFormat(url);
if (setDevicePixelRatio)
devicePixelRatio = targetDevicePixelRatio;
@@ -144,7 +135,7 @@ QSize QQuickImageBase::sourceSize() const
int width = d->sourcesize.width();
int height = d->sourcesize.height();
- return QSize(width != -1 ? width : d->pix.width(), height != -1 ? height : d->pix.height());
+ return QSize(width != -1 ? width : d->currentPix->width(), height != -1 ? height : d->currentPix->height());
}
void QQuickImageBase::resetSourceSize()
@@ -197,7 +188,7 @@ void QQuickImageBase::setCache(bool cache)
QImage QQuickImageBase::image() const
{
Q_D(const QQuickImageBase);
- return d->pix.image();
+ return d->currentPix->image();
}
void QQuickImageBase::setMirror(bool mirror)
@@ -243,7 +234,7 @@ bool QQuickImageBase::mirrorVertically() const
void QQuickImageBase::setCurrentFrame(int frame)
{
Q_D(QQuickImageBase);
- if (frame == d->currentFrame || frame < 0 || (isComponentComplete() && frame >= d->pix.frameCount()))
+ if (frame == d->currentFrame || frame < 0 || (isComponentComplete() && frame >= d->currentPix->frameCount()))
return;
d->currentFrame = frame;
@@ -273,7 +264,8 @@ int QQuickImageBase::frameCount() const
void QQuickImageBase::loadEmptyUrl()
{
Q_D(QQuickImageBase);
- d->pix.clear(this);
+ d->currentPix->clear(this);
+ d->pendingPix->clear(this);
d->setProgress(0);
d->status = Null; // do not emit statusChanged until after setImplicitSize
setImplicitSize(0, 0); // also called in QQuickImageBase::pixmapChange, but not QQuickImage/QQuickBorderImage overrides
@@ -299,7 +291,7 @@ void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
options |= QQuickPixmap::Asynchronous;
if (d->cache)
options |= QQuickPixmap::Cache;
- d->pix.clear(this);
+ d->pendingPix->clear(this);
QUrl loadUrl = url;
const QQmlContext *context = qmlContext(this);
if (context)
@@ -310,7 +302,7 @@ void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
d->devicePixelRatio = 1.0;
bool updatedDevicePixelRatio = false;
if (d->sourcesize.isValid()
- || (isScalableImageFormat(d->url) && d->url.scheme() != QLatin1String("image"))) {
+ || (QQuickPixmap::isScalableImageFormat(d->url) && d->url.scheme() != "image"_L1)) {
updatedDevicePixelRatio = d->updateDevicePixelRatio(targetDevicePixelRatio);
}
@@ -324,16 +316,16 @@ void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
d->status = Null; // reset status, no emit
- d->pix.load(qmlEngine(this),
- loadUrl,
- d->sourceClipRect.toRect(),
- (loadOptions & HandleDPR) ? d->sourcesize * d->devicePixelRatio : QSize(),
- options,
- (loadOptions & UseProviderOptions) ? d->providerOptions : QQuickImageProviderOptions(),
- d->currentFrame, d->frameCount,
- d->devicePixelRatio);
+ d->pendingPix->load(qmlEngine(this),
+ loadUrl,
+ d->sourceClipRect.toRect(),
+ (loadOptions & HandleDPR) ? d->sourcesize * d->devicePixelRatio : QSize(),
+ options,
+ (loadOptions & UseProviderOptions) ? d->providerOptions : QQuickImageProviderOptions(),
+ d->currentFrame, d->frameCount,
+ d->devicePixelRatio);
- if (d->pix.isLoading()) {
+ if (d->pendingPix->isLoading()) {
d->setProgress(0);
d->setStatus(Loading);
@@ -346,9 +338,10 @@ void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
QQuickImageBase::staticMetaObject.indexOfSlot("requestFinished()");
}
- d->pix.connectFinished(this, thisRequestFinished);
- d->pix.connectDownloadProgress(this, thisRequestProgress);
- update(); //pixmap may have invalidated texture, updatePaintNode needs to be called before the next repaint
+ d->pendingPix->connectFinished(this, thisRequestFinished);
+ d->pendingPix->connectDownloadProgress(this, thisRequestProgress);
+ if (!d->retainWhileLoading)
+ update(); //pixmap may have invalidated texture, updatePaintNode needs to be called before the next repaint
} else {
requestFinished();
}
@@ -369,10 +362,15 @@ void QQuickImageBase::load()
void QQuickImageBase::requestFinished()
{
Q_D(QQuickImageBase);
+ if (d->pendingPix != d->currentPix
+ && d->pendingPix->status() != QQuickPixmap::Null
+ && d->pendingPix->status() != QQuickPixmap::Loading) {
+ std::swap(d->pendingPix, d->currentPix);
+ d->pendingPix->clear(this); // Clear the old image
+ }
- if (d->pix.isError()) {
- qmlWarning(this) << d->pix.error();
- d->pix.clear(this);
+ if (d->currentPix->isError()) {
+ qmlWarning(this) << d->currentPix->error();
d->status = Error;
d->setProgress(0);
} else {
@@ -391,12 +389,12 @@ void QQuickImageBase::requestFinished()
d->oldAutoTransform = autoTransform();
emitAutoTransformBaseChanged();
}
- if (d->frameCount != d->pix.frameCount()) {
- d->frameCount = d->pix.frameCount();
+ if (d->frameCount != d->currentPix->frameCount()) {
+ d->frameCount = d->currentPix->frameCount();
emit frameCountChanged();
}
- if (d->colorSpace != d->pix.colorSpace()) {
- d->colorSpace = d->pix.colorSpace();
+ if (d->colorSpace != d->currentPix->colorSpace()) {
+ d->colorSpace = d->currentPix->colorSpace();
emit colorSpaceChanged();
}
@@ -439,7 +437,7 @@ void QQuickImageBase::componentComplete()
void QQuickImageBase::pixmapChange()
{
Q_D(QQuickImageBase);
- setImplicitSize(d->pix.width() / d->devicePixelRatio, d->pix.height() / d->devicePixelRatio);
+ setImplicitSize(d->currentPix->width() / d->devicePixelRatio, d->currentPix->height() / d->devicePixelRatio);
}
void QQuickImageBase::resolve2xLocalFile(const QUrl &url, qreal targetDevicePixelRatio, QUrl *sourceUrl, qreal *sourceDevicePixelRatio)
@@ -479,7 +477,7 @@ bool QQuickImageBase::autoTransform() const
{
Q_D(const QQuickImageBase);
if (d->providerOptions.autoTransform() == QQuickImageProviderOptions::UsePluginDefaultTransform)
- return d->pix.autoTransform() == QQuickImageProviderOptions::ApplyTransform;
+ return d->currentPix->autoTransform() == QQuickImageProviderOptions::ApplyTransform;
return d->providerOptions.autoTransform() == QQuickImageProviderOptions::ApplyTransform;
}
@@ -509,6 +507,30 @@ void QQuickImageBase::setColorSpace(const QColorSpace &colorSpace)
emit colorSpaceChanged();
}
+bool QQuickImageBase::retainWhileLoading() const
+{
+ Q_D(const QQuickImageBase);
+ return d->retainWhileLoading;
+}
+
+void QQuickImageBase::setRetainWhileLoading(bool retainWhileLoading)
+{
+ Q_D(QQuickImageBase);
+ if (d->retainWhileLoading == retainWhileLoading)
+ return;
+
+ d->retainWhileLoading = retainWhileLoading;
+ if (d->retainWhileLoading) {
+ if (d->currentPix == &d->pix1)
+ d->pendingPix = &d->pix2;
+ else
+ d->pendingPix = &d->pix1;
+ } else {
+ d->pendingPix->clear();
+ d->pendingPix = d->currentPix;
+ }
+}
+
QT_END_NAMESPACE
#include "moc_qquickimagebase_p.cpp"
diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h
index 08f9abbc63..5a33db43b8 100644
--- a/src/quick/items/qquickimagebase_p.h
+++ b/src/quick/items/qquickimagebase_p.h
@@ -33,6 +33,7 @@ class Q_QUICK_EXPORT QQuickImageBase : public QQuickImplicitSizeItem
Q_PROPERTY(bool cache READ cache WRITE setCache NOTIFY cacheChanged)
Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged)
Q_PROPERTY(bool mirrorVertically READ mirrorVertically WRITE setMirrorVertically NOTIFY mirrorVerticallyChanged REVISION(6, 2))
+ Q_PROPERTY(bool retainWhileLoading READ retainWhileLoading WRITE setRetainWhileLoading NOTIFY retainWhileLoadingChanged REVISION(6, 8))
Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged REVISION(2, 14))
Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged REVISION(2, 14))
Q_PROPERTY(QColorSpace colorSpace READ colorSpace WRITE setColorSpace NOTIFY colorSpaceChanged REVISION(2, 15))
@@ -94,6 +95,9 @@ public:
QColorSpace colorSpace() const;
virtual void setColorSpace(const QColorSpace &colorSpace);
+ bool retainWhileLoading() const;
+ void setRetainWhileLoading(bool retain);
+
static void resolve2xLocalFile(const QUrl &url, qreal targetDevicePixelRatio, QUrl *sourceUrl, qreal *sourceDevicePixelRatio);
// Use a virtual rather than a signal->signal to avoid the huge
@@ -113,6 +117,7 @@ Q_SIGNALS:
Q_REVISION(2, 15) void sourceClipRectChanged();
Q_REVISION(2, 15) void colorSpaceChanged();
Q_REVISION(6, 2) void mirrorVerticallyChanged();
+ Q_REVISION(6, 8) void retainWhileLoadingChanged();
protected:
void loadEmptyUrl();
diff --git a/src/quick/items/qquickimagebase_p_p.h b/src/quick/items/qquickimagebase_p_p.h
index 3cbb9facb0..d53712b779 100644
--- a/src/quick/items/qquickimagebase_p_p.h
+++ b/src/quick/items/qquickimagebase_p_p.h
@@ -33,8 +33,11 @@ public:
cache(true),
mirrorHorizontally(false),
mirrorVertically(false),
- oldAutoTransform(false)
+ oldAutoTransform(false),
+ retainWhileLoading(false)
{
+ pendingPix = &pix1;
+ currentPix = &pix1;
}
virtual bool updateDevicePixelRatio(qreal targetDevicePixelRatio);
@@ -43,7 +46,10 @@ public:
void setProgress(qreal value);
QUrl url;
- QQuickPixmap pix;
+ QQuickPixmap *pendingPix = nullptr;
+ QQuickPixmap *currentPix = nullptr;
+ QQuickPixmap pix1;
+ QQuickPixmap pix2;
QSize sourcesize;
QSize oldSourceSize;
QRectF sourceClipRect;
@@ -61,6 +67,7 @@ public:
bool mirrorHorizontally: 1;
bool mirrorVertically : 1;
bool oldAutoTransform : 1;
+ bool retainWhileLoading : 1;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index a9a5c4c4a2..e7b2a31f04 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -2470,12 +2470,32 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item)
*/
bool QQuickItemPrivate::focusNextPrev(QQuickItem *item, bool forward)
{
- QQuickItem *next = QQuickItemPrivate::nextPrevItemInTabFocusChain(item, forward);
+ QQuickWindow *window = item->window();
+ const bool wrap = !window || window->isTopLevel();
+
+ QQuickItem *next = QQuickItemPrivate::nextPrevItemInTabFocusChain(item, forward, wrap);
if (next == item)
return false;
- next->forceActiveFocus(forward ? Qt::TabFocusReason : Qt::BacktabFocusReason);
+ const auto reason = forward ? Qt::TabFocusReason : Qt::BacktabFocusReason;
+
+ if (!wrap && !next) {
+ // Focus chain wrapped and we are not top-level window
+ // Give focus to parent window
+ Q_ASSERT(window);
+ Q_ASSERT(window->parent());
+
+
+ qt_window_private(window->parent())->setFocusToTarget(
+ forward ? QWindowPrivate::FocusTarget::Next
+ : QWindowPrivate::FocusTarget::Prev,
+ reason);
+ window->parent()->requestActivate();
+ return true;
+ }
+
+ next->forceActiveFocus(reason);
return true;
}
@@ -2524,7 +2544,7 @@ QQuickItem *QQuickItemPrivate::prevTabChildItem(const QQuickItem *item, int star
return nullptr;
}
-QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, bool forward)
+QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, bool forward, bool wrap)
{
Q_ASSERT(item);
qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: item:" << item << ", forward:" << forward;
@@ -2618,6 +2638,14 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
}
current = parent;
} else if (hasChildren) {
+ if (!wrap && (forward || firstFromItem != from)) {
+ qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain:"
+ << "Focus chain about to wrap.";
+ // If focus chain wraps, we should give the parent window
+ // a chance to get focus, so we should stop here
+ return nullptr;
+ }
+
// Wrap around after checking all items forward
if (forward) {
current = firstChild;
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index c2e014b72d..bb238904ca 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -575,7 +575,7 @@ public:
static bool focusNextPrev(QQuickItem *item, bool forward);
static QQuickItem *nextTabChildItem(const QQuickItem *item, int start);
static QQuickItem *prevTabChildItem(const QQuickItem *item, int start);
- static QQuickItem *nextPrevItemInTabFocusChain(QQuickItem *item, bool forward);
+ static QQuickItem *nextPrevItemInTabFocusChain(QQuickItem *item, bool forward, bool wrap = true);
static bool canAcceptTabFocus(QQuickItem *item);
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 9c83183eb7..a6edfc4754 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -1284,6 +1284,7 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventS
return me.isAccepted();
}
+ Q_UNUSED(source)
return false;
}
diff --git a/src/quick/items/qquickpalettecolorprovider.cpp b/src/quick/items/qquickpalettecolorprovider.cpp
index af6f0ef7a5..f01fa22bdd 100644
--- a/src/quick/items/qquickpalettecolorprovider.cpp
+++ b/src/quick/items/qquickpalettecolorprovider.cpp
@@ -162,6 +162,7 @@ bool QQuickPaletteColorProvider::doInheritPalette(const QPalette &palette)
{
auto inheritedMask = m_requestedPalette.isAllocated() ? m_requestedPalette->resolveMask() | palette.resolveMask()
: palette.resolveMask();
+ // If a palette was set on this item, it should always win over the palette to be inherited from.
QPalette parentPalette = m_requestedPalette.isAllocated() ? m_requestedPalette->resolve(palette) : palette;
parentPalette.setResolveMask(inheritedMask);
diff --git a/src/quick/items/qquickselectable_p.h b/src/quick/items/qquickselectable_p.h
index dbee64c49e..65434be490 100644
--- a/src/quick/items/qquickselectable_p.h
+++ b/src/quick/items/qquickselectable_p.h
@@ -37,7 +37,7 @@ public:
virtual void normalizeSelection() = 0;
virtual QRectF selectionRectangle() const = 0;
- virtual QSizeF scrollTowardsSelectionPoint(const QPointF &pos, const QSizeF &step) = 0;
+ virtual QSizeF scrollTowardsPoint(const QPointF &pos, const QSizeF &step) = 0;
virtual void setCallback(std::function<void(CallBackFlag)> func) = 0;
};
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 6203f6f3c1..c7bd050327 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -6,11 +6,13 @@
#include <QtCore/qtimer.h>
#include <QtCore/qdir.h>
+#include <QtCore/qmimedata.h>
#include <QtQmlModels/private/qqmldelegatemodel_p.h>
#include <QtQmlModels/private/qqmldelegatemodel_p_p.h>
#include <QtQml/private/qqmlincubator_p.h>
#include <QtQmlModels/private/qqmlchangeset_p.h>
#include <QtQml/qqmlinfo.h>
+#include <QtQuick/qquickitemgrabresult.h>
#include <QtQuick/private/qquickflickable_p_p.h>
#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
@@ -467,6 +469,9 @@
\li required property bool current - \c true if the delegate is \l {Keyboard navigation}{current.}
\li required property bool selected - \c true if the delegate is \l {Selecting items}{selected.}
\li required property bool editing - \c true if the delegate is being \l {Editing cells}{edited.}
+ \li required property bool containsDrag - \c true if a column or row is currently being dragged
+ over this delegate. This property is only supported for HorizontalHeaderView and
+ VerticalHeaderView. (since Qt 6.8)
\endlist
The following example shows how to use these properties:
@@ -944,6 +949,48 @@
*/
/*!
+ \qmlmethod QtQuick::TableView::moveColumn(int source, int destination)
+ \since 6.8
+
+ Moves a column from the \a source to the \a destination position.
+
+ \note If a syncView is set, the sync view will control the internal index mapping for
+ column reordering. Therefore, in that case, a call to this function will be forwarded to
+ the sync view instead.
+*/
+
+/*!
+ \qmlmethod QtQuick::TableView::clearColumnReordering()
+ \since 6.8
+
+ Resets any previously applied column reordering.
+
+ \note If a syncView is set, a call to this function will be forwarded to
+ corresponding view item and reset the column ordering.
+*/
+
+/*!
+ \qmlmethod QtQuick::TableView::moveRow(int source, int destination)
+ \since 6.8
+
+ Moves a row from the \a source to the \a destination position.
+
+ \note If a syncView is set, the sync view will control the internal index mapping for
+ row reordering. Therefore, in that case, a call to this function will be forwarded to
+ the sync view instead.
+*/
+
+/*!
+ \qmlmethod QtQuick::TableView::clearRowReordering()
+ \since 6.8
+
+ Resets any previously applied row reordering.
+
+ \note If a syncView is set, a call to this function will be forwarded to
+ the corresponding view item and reset the row ordering.
+*/
+
+/*!
\qmlmethod Item QtQuick::TableView::itemAtCell(point cell)
Returns the delegate item at \a cell if loaded, otherwise \c null.
@@ -1339,6 +1386,24 @@
*/
/*!
+ \qmlsignal QtQuick::TableView::columnMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex)
+ \since 6.8
+
+ This signal is emitted when a column is moved. The column's logical index is specified by
+ \a logicalIndex, the old index by \a oldVisualIndex, and the new index position by
+ \a newVisualIndex.
+*/
+
+/*!
+ \qmlsignal QtQuick::TableView::rowMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex)
+ \since 6.8
+
+ This signal is emitted when a row is moved. The row's logical index is specified by
+ \a logicalIndex, the old index by \a oldVisualIndex, and the new index position by
+ \a newVisualIndex.
+*/
+
+/*!
\qmlattachedproperty TableView QtQuick::TableView::view
This attached property holds the view that manages the delegate instance.
@@ -1459,6 +1524,7 @@ static const char* kRequiredProperties = "_qt_tableview_requiredpropertymask";
static const char* kRequiredProperty_selected = "selected";
static const char* kRequiredProperty_current = "current";
static const char* kRequiredProperty_editing = "editing";
+static const char* kRequiredProperty_containsDrag = "containsDrag";
QDebug operator<<(QDebug dbg, QQuickTableViewPrivate::RebuildState state)
{
@@ -1849,28 +1915,43 @@ void QQuickTableViewPrivate::updateSelection(const QRect &oldSelection, const QR
{
const QModelIndex startIndex = qaim->index(newRect.y(), newRect.x());
const QModelIndex endIndex = qaim->index(newRect.y() + newRect.height(), newRect.x() + newRect.width());
- select = QItemSelection(startIndex, endIndex);
+ for (const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
+ const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
+ select.append(QItemSelection(logicalModelIndex, logicalModelIndex));
+ }
}
// Unselect cells in the new minus old rects
if (oldRect.x() < newRect.x()) {
const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), newRect.x() - 1);
- deselect.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
+ for (const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
+ const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
+ deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
+ }
} else if (oldRect.x() + oldRect.width() > newRect.x() + newRect.width()) {
const QModelIndex startIndex = qaim->index(oldRect.y(), newRect.x() + newRect.width() + 1);
const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
- deselect.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
+ for (auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
+ const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
+ deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
+ }
}
if (oldRect.y() < newRect.y()) {
const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
const QModelIndex endIndex = qaim->index(newRect.y() - 1, oldRect.x() + oldRect.width());
- deselect.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
+ for (const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
+ const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
+ deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
+ }
} else if (oldRect.y() + oldRect.height() > newRect.y() + newRect.height()) {
const QModelIndex startIndex = qaim->index(newRect.y() + newRect.height() + 1, oldRect.x());
const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
- deselect.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
+ for (const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
+ const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
+ deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
+ }
}
if (selectionFlag == QItemSelectionModel::Select) {
@@ -1976,7 +2057,7 @@ QRect QQuickTableViewPrivate::selection() const
return QRect(selectionStartCell.x(), selectionStartCell.y(), w, h);
}
-QSizeF QQuickTableViewPrivate::scrollTowardsSelectionPoint(const QPointF &pos, const QSizeF &step)
+QSizeF QQuickTableViewPrivate::scrollTowardsPoint(const QPointF &pos, const QSizeF &step)
{
Q_Q(QQuickTableView);
@@ -2085,14 +2166,14 @@ QPoint QQuickTableViewPrivate::cellAtModelIndex(int modelIndex) const
}
}
-int QQuickTableViewPrivate::modelIndexToCellIndex(const QModelIndex &modelIndex) const
+int QQuickTableViewPrivate::modelIndexToCellIndex(const QModelIndex &modelIndex, bool visualIndex) const
{
// Convert QModelIndex to cell index. A cell index is just an
// integer representation of a cell instead of using a QPoint.
const QPoint cell = q_func()->cellAtIndex(modelIndex);
if (!cellIsValid(cell))
return -1;
- return modelIndexAtCell(cell);
+ return modelIndexAtCell(visualIndex ? cell : QPoint(modelIndex.column(), modelIndex.row()));
}
int QQuickTableViewPrivate::edgeToArrayIndex(Qt::Edge edge) const
@@ -2647,7 +2728,9 @@ FxTableItem *QQuickTableViewPrivate::createFxTableItem(const QPoint &cell, QQmlI
Q_Q(QQuickTableView);
bool ownItem = false;
- int modelIndex = modelIndexAtCell(cell);
+
+ int modelIndex = modelIndexAtCell(isTransposed ? QPoint(logicalRowIndex(cell.x()), logicalColumnIndex(cell.y())) :
+ QPoint(logicalColumnIndex(cell.x()), logicalRowIndex(cell.y())));
QObject* object = model->object(modelIndex, incubationMode);
if (!object) {
@@ -3000,7 +3083,7 @@ qreal QQuickTableViewPrivate::getColumnWidth(int column) const
const int noExplicitColumnWidth = -1;
- if (cachedColumnWidth.startIndex == column)
+ if (cachedColumnWidth.startIndex == logicalColumnIndex(column))
return cachedColumnWidth.size;
if (syncHorizontally)
@@ -3019,7 +3102,7 @@ qreal QQuickTableViewPrivate::getColumnWidth(int column) const
qreal columnWidth = noExplicitColumnWidth;
if (columnWidthProvider.isCallable()) {
- auto const columnAsArgument = QJSValueList() << QJSValue(column);
+ auto const columnAsArgument = QJSValueList() << QJSValue(logicalColumnIndex(column));
columnWidth = columnWidthProvider.call(columnAsArgument).toNumber();
if (qIsNaN(columnWidth) || columnWidth < 0)
columnWidth = noExplicitColumnWidth;
@@ -3031,7 +3114,7 @@ qreal QQuickTableViewPrivate::getColumnWidth(int column) const
columnWidth = noExplicitColumnWidth;
}
- cachedColumnWidth.startIndex = column;
+ cachedColumnWidth.startIndex = logicalColumnIndex(column);
cachedColumnWidth.size = columnWidth;
return columnWidth;
}
@@ -3046,7 +3129,7 @@ qreal QQuickTableViewPrivate::getRowHeight(int row) const
const int noExplicitRowHeight = -1;
- if (cachedRowHeight.startIndex == row)
+ if (cachedRowHeight.startIndex == logicalRowIndex(row))
return cachedRowHeight.size;
if (syncVertically)
@@ -3065,7 +3148,7 @@ qreal QQuickTableViewPrivate::getRowHeight(int row) const
qreal rowHeight = noExplicitRowHeight;
if (rowHeightProvider.isCallable()) {
- auto const rowAsArgument = QJSValueList() << QJSValue(row);
+ auto const rowAsArgument = QJSValueList() << QJSValue(logicalRowIndex(row));
rowHeight = rowHeightProvider.call(rowAsArgument).toNumber();
if (qIsNaN(rowHeight) || rowHeight < 0)
rowHeight = noExplicitRowHeight;
@@ -3077,7 +3160,7 @@ qreal QQuickTableViewPrivate::getRowHeight(int row) const
rowHeight = noExplicitRowHeight;
}
- cachedRowHeight.startIndex = row;
+ cachedRowHeight.startIndex = logicalRowIndex(row);
cachedRowHeight.size = rowHeight;
return rowHeight;
}
@@ -4288,11 +4371,13 @@ void QQuickTableViewPrivate::initItemCallback(int modelIndex, QObject *object)
item->setZ(1);
const QPoint cell = cellAtModelIndex(modelIndex);
- const bool current = currentInSelectionModel(cell);
- const bool selected = selectedInSelectionModel(cell);
+ const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
+ const bool current = currentInSelectionModel(visualCell);
+ const bool selected = selectedInSelectionModel(visualCell);
setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), modelIndex, object, true);
setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), modelIndex, object, true);
setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(false), modelIndex, item, true);
+ setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(false), modelIndex, item, true);
if (auto attached = getAttachedObject(object))
attached->setView(q);
@@ -4309,11 +4394,13 @@ void QQuickTableViewPrivate::itemPooledCallback(int modelIndex, QObject *object)
void QQuickTableViewPrivate::itemReusedCallback(int modelIndex, QObject *object)
{
const QPoint cell = cellAtModelIndex(modelIndex);
- const bool current = currentInSelectionModel(cell);
- const bool selected = selectedInSelectionModel(cell);
+ const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
+ const bool current = currentInSelectionModel(visualCell);
+ const bool selected = selectedInSelectionModel(visualCell);
setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), modelIndex, object, false);
setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), modelIndex, object, false);
// Note: the edit item will never be reused, so no reason to set kRequiredProperty_editing
+ setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(false), modelIndex, object, false);
if (auto item = qobject_cast<QQuickItem*>(object))
QQuickItemPrivate::get(item)->setCulled(false);
@@ -4896,6 +4983,7 @@ void QQuickTableViewPrivate::init()
hoverHandler = new QQuickTableViewHoverHandler(q);
resizeHandler = new QQuickTableViewResizeHandler(q);
+
hoverHandler->setEnabled(resizableRows || resizableColumns);
resizeHandler->setEnabled(resizableRows || resizableColumns);
@@ -5668,6 +5756,10 @@ void QQuickTableView::setSyncView(QQuickTableView *view)
if (d->assignedSyncView == view)
return;
+ // Clear existing index mapping information maintained
+ // in the current view
+ d->clearIndexMapping();
+
d->assignedSyncView = view;
d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
@@ -6012,6 +6104,169 @@ void QQuickTableView::positionViewAtCell(int column, int row, PositionMode mode,
}
#endif
+void QQuickTableView::moveColumn(int source, int destination)
+{
+ Q_D(QQuickTableView);
+ d->moveSection(source, destination, Qt::Horizontal);
+}
+
+void QQuickTableView::moveRow(int source, int destination)
+{
+ Q_D(QQuickTableView);
+ d->moveSection(source, destination, Qt::Vertical);
+}
+
+void QQuickTableViewPrivate::moveSection(int source, int destination, Qt::Orientations orientation)
+{
+ Q_Q(QQuickTableView);
+
+ if (source < 0 || destination < 0 ||
+ (orientation == Qt::Horizontal &&
+ (source >= tableSize.width() || destination >= tableSize.width())) ||
+ (orientation == Qt::Vertical &&
+ (source >= tableSize.height() || destination >= tableSize.height())))
+ return;
+
+ if (source == destination)
+ return;
+
+ if (m_sectionState != SectionState::Moving) {
+ m_sectionState = SectionState::Moving;
+ if (syncView)
+ syncView->d_func()->moveSection(source, destination, orientation);
+ else {
+ // Initialize the visual and logical index mapping
+ initializeIndexMapping();
+
+ // Set current index mapping according to moving rows or columns
+ SectionData *visualIndex = nullptr;
+ SectionData *logicalIndex = nullptr;
+
+ if (orientation == Qt::Horizontal) {
+ visualIndex = visualIndices[0].data();
+ logicalIndex = logicalIndices[0].data();
+ } else if (orientation == Qt::Vertical) {
+ visualIndex = visualIndices[1].data();
+ logicalIndex = logicalIndices[1].data();
+ }
+
+ const int logical = logicalIndex[source].index;
+ int visual = source;
+
+ if (destination > source) {
+ while (visual < destination) {
+ SectionData &visualData = visualIndex[logicalIndex[visual + 1].index];
+ SectionData &logicalData = logicalIndex[visual];
+ visualData.prevIndex = visualData.index;
+ visualData.index = visual;
+ logicalData.prevIndex = logicalData.index;
+ logicalData.index = logicalIndex[visual + 1].index;
+ ++visual;
+ }
+ } else {
+ while (visual > destination) {
+ SectionData &visualData = visualIndex[logicalIndex[visual - 1].index];
+ SectionData &logicalData = logicalIndex[visual];
+ visualData.prevIndex = visualData.index;
+ visualData.index = visual;
+ logicalData.prevIndex = logicalData.index;
+ logicalData.index = logicalIndex[visual - 1].index;
+ --visual;
+ }
+ }
+
+ visualIndex[logical].prevIndex = visualIndex[logical].index;
+ visualIndex[logical].index = destination;
+ logicalIndex[destination].prevIndex = logicalIndex[destination].index;
+ logicalIndex[destination].index = logical;
+
+ // Trigger section move for horizontal and vertical child views
+ // Used in a case where moveSection() triggered for table view
+ for (auto syncChild : std::as_const(syncChildren)) {
+ auto syncChild_d = syncChild->d_func();
+ if (syncChild_d->m_sectionState != SectionState::Moving &&
+ ((syncChild_d->syncHorizontally && orientation == Qt::Horizontal) ||
+ (syncChild_d->syncVertically && orientation == Qt::Vertical)))
+ syncChild_d->moveSection(source, destination, orientation);
+ }
+ }
+
+ // Rebuild the view to reflect the section order
+ scheduleRebuildTable(RebuildOption::ViewportOnly);
+ m_sectionState = SectionState::Idle;
+
+ // Emit section moved signal for the sections moved in the view
+ const int startIndex = (source > destination) ? destination : source;
+ const int endIndex = (source > destination) ? source : destination;
+ const int mapIndex = static_cast<int>(orientation) - 1;
+ for (int index = startIndex; index <= endIndex; index++) {
+ const SectionData *logicalDataIndices = (syncView ? syncView->d_func()->logicalIndices[mapIndex].constData() : logicalIndices[mapIndex].constData());
+ const SectionData *visualDataIndices = syncView ? syncView->d_func()->visualIndices[mapIndex].constData() : visualIndices[mapIndex].constData();
+ const int prevLogicalIndex = logicalDataIndices[index].prevIndex;
+ if (orientation == Qt::Horizontal)
+ emit q->columnMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
+ else
+ emit q->rowMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
+ }
+ }
+}
+
+void QQuickTableView::clearColumnReordering()
+{
+ Q_D(QQuickTableView);
+ d->clearSection(Qt::Horizontal);
+}
+
+void QQuickTableView::clearRowReordering()
+{
+ Q_D(QQuickTableView);
+ d->clearSection(Qt::Vertical);
+}
+
+void QQuickTableViewPrivate::clearSection(Qt::Orientations orientation)
+{
+ Q_Q(QQuickTableView);
+
+ const int mapIndex = static_cast<int>(orientation) - 1;
+ const QList<SectionData> oldLogicalIndices = syncView ? syncView->d_func()->logicalIndices[mapIndex] : logicalIndices[mapIndex];
+ const QList<SectionData> oldVisualIndices = syncView ? syncView->d_func()->visualIndices[mapIndex] : visualIndices[mapIndex];;
+
+ if (syncView)
+ syncView->d_func()->clearSection(orientation);
+ else {
+ // Clear the index mapping and rebuild the table
+ logicalIndices[mapIndex].clear();
+ visualIndices[mapIndex].clear();
+ scheduleRebuildTable(RebuildOption::ViewportOnly);
+ }
+
+ // Emit section moved signal for the sections moved in the view
+ for (int index = 0; index < oldLogicalIndices.size(); index++) {
+ const SectionData *logicalDataIndices = oldLogicalIndices.constData();
+ const SectionData *visualDataIndices = oldVisualIndices.constData();
+ if (logicalDataIndices[index].index != index) {
+ const int currentIndex = logicalDataIndices[index].index;
+ if (orientation == Qt::Horizontal)
+ emit q->columnMoved(currentIndex, visualDataIndices[currentIndex].index, index);
+ else
+ emit q->rowMoved(currentIndex, visualDataIndices[currentIndex].index, index);
+ }
+ }
+}
+
+void QQuickTableViewPrivate::setContainsDragOnDelegateItem(const QModelIndex &modelIndex, bool overlay)
+{
+ if (!modelIndex.isValid())
+ return;
+
+ const int cellIndex = modelIndexToCellIndex(modelIndex);
+ if (!loadedItems.contains(cellIndex))
+ return;
+ const QPoint cell = cellAtModelIndex(cellIndex);
+ QQuickItem *item = loadedTableItem(cell)->item;
+ setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(overlay), cellIndex, item, false);
+}
+
QQuickItem *QQuickTableView::itemAtCell(const QPoint &cell) const
{
Q_D(const QQuickTableView);
@@ -6190,9 +6445,9 @@ void QQuickTableView::setColumnWidth(int column, qreal size)
return;
if (size < 0)
- d->explicitColumnWidths.remove(column);
+ d->explicitColumnWidths.remove(d->logicalColumnIndex(column));
else
- d->explicitColumnWidths.insert(column, size);
+ d->explicitColumnWidths.insert(d->logicalColumnIndex(column), size);
if (d->loadedItems.isEmpty())
return;
@@ -6225,7 +6480,7 @@ qreal QQuickTableView::explicitColumnWidth(int column) const
if (d->syncHorizontally)
return d->syncView->explicitColumnWidth(column);
- const auto it = d->explicitColumnWidths.constFind(column);
+ const auto it = d->explicitColumnWidths.constFind(d->logicalColumnIndex(column));
if (it != d->explicitColumnWidths.constEnd())
return *it;
return -1;
@@ -6248,9 +6503,9 @@ void QQuickTableView::setRowHeight(int row, qreal size)
return;
if (size < 0)
- d->explicitRowHeights.remove(row);
+ d->explicitRowHeights.remove(d->logicalRowIndex(row));
else
- d->explicitRowHeights.insert(row, size);
+ d->explicitRowHeights.insert(d->logicalRowIndex(row), size);
if (d->loadedItems.isEmpty())
return;
@@ -6283,7 +6538,7 @@ qreal QQuickTableView::explicitRowHeight(int row) const
if (d->syncVertically)
return d->syncView->explicitRowHeight(row);
- const auto it = d->explicitRowHeights.constFind(row);
+ const auto it = d->explicitRowHeights.constFind(d->logicalRowIndex(row));
if (it != d->explicitRowHeights.constEnd())
return *it;
return -1;
@@ -6299,14 +6554,15 @@ QModelIndex QQuickTableView::modelIndex(const QPoint &cell) const
if (!qaim)
return {};
- return qaim->index(cell.y(), cell.x());
+ return qaim->index(d->logicalRowIndex(cell.y()), d->logicalColumnIndex(cell.x()));
}
QPoint QQuickTableView::cellAtIndex(const QModelIndex &index) const
{
if (!index.isValid() || index.parent().isValid())
return {-1, -1};
- return {index.column(), index.row()};
+ Q_D(const QQuickTableView);
+ return {d->visualColumnIndex(index.column()), d->visualRowIndex(index.row())};
}
#if QT_DEPRECATED_SINCE(6, 4)
@@ -6371,7 +6627,8 @@ void QQuickTableView::edit(const QModelIndex &index)
// is currently dependent of the QQmlTableInstanceModel that was used to create the object
// in order to initialize required properties, so we need to set the editItem variable
// early on, so that we can use it in setRequiredProperty.
- d->editIndex = modelIndex(d->cellAtModelIndex(serializedModelIndex));
+ const QPoint cell = d->cellAtModelIndex(serializedModelIndex);
+ d->editIndex = modelIndex({d->visualColumnIndex(cell.x()), d->visualRowIndex(cell.y())});
d->editItem = qmlobject_cast<QQuickItem*>(object);
if (!d->editItem)
return;
@@ -6400,7 +6657,7 @@ void QQuickTableView::edit(const QModelIndex &index)
d->editModel->setModel(d->tableModel->model());
d->editModel->setDelegate(attached->editDelegate());
- const int cellIndex = d->modelIndexToCellIndex(index);
+ const int cellIndex = d->modelIndexToCellIndex(index, false);
QObject* object = d->editModel->object(cellIndex, QQmlIncubator::Synchronous);
if (!object) {
d->editIndex = QModelIndex();
@@ -6451,7 +6708,7 @@ void QQuickTableView::closeEditor()
d->editItem = nullptr;
cellItem->setZ(1);
- const int cellIndex = d->modelIndexToCellIndex(d->editIndex);
+ const int cellIndex = d->modelIndexToCellIndex(d->editIndex, false);
d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(false), cellIndex, cellItem, false);
// Remove the extra reference we sat on the cell item from edit()
d->model->release(cellItem, QQmlInstanceModel::NotReusable);
@@ -6669,7 +6926,6 @@ void QQuickTableView::setResizableRows(bool enabled)
}
// ----------------------------------------------
-
QQuickTableViewHoverHandler::QQuickTableViewHoverHandler(QQuickTableView *view)
: QQuickHoverHandler(view->contentItem())
{
@@ -6720,13 +6976,35 @@ void QQuickTableViewHoverHandler::handleEventPoint(QPointerEvent *event, QEventP
// ----------------------------------------------
-QQuickTableViewResizeHandler::QQuickTableViewResizeHandler(QQuickTableView *view)
+QQuickTableViewPointerHandler::QQuickTableViewPointerHandler(QQuickTableView *view)
: QQuickSinglePointHandler(view->contentItem())
{
- setMargin(5);
// Set a grab permission that stops the flickable, as well as
// any drag handler inside the delegate, from stealing the drag.
setGrabPermissions(QQuickPointerHandler::CanTakeOverFromAnything);
+}
+
+bool QQuickTableViewPointerHandler::wantsEventPoint(const QPointerEvent *event, const QEventPoint &point)
+{
+ if (!QQuickSinglePointHandler::wantsEventPoint(event, point))
+ return false;
+
+ // If we have a mouse wheel event then we do not want to do anything related to resizing.
+ if (event->type() == QEvent::Type::Wheel)
+ return false;
+
+ // When the user is flicking, we disable resizing, so that
+ // he doesn't start to resize by accident.
+ const auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ return !tableView->isMoving();
+}
+
+// ----------------------------------------------
+
+QQuickTableViewResizeHandler::QQuickTableViewResizeHandler(QQuickTableView *view)
+ : QQuickTableViewPointerHandler(view)
+{
+ setMargin(5);
setObjectName("tableViewResizeHandler");
}
@@ -6754,23 +7032,14 @@ void QQuickTableViewResizeHandler::onGrabChanged(QQuickPointerHandler *grabber
}
}
-bool QQuickTableViewResizeHandler::wantsEventPoint(const QPointerEvent *event, const QEventPoint &point)
-{
- if (!QQuickSinglePointHandler::wantsEventPoint(event, point))
- return false;
-
- // If we have a mouse wheel event then we do not want to do anything related to resizing.
- if (event->type() == QEvent::Type::Wheel)
- return false;
-
- // When the user is flicking, we disable resizing, so that
- // he doesn't start to resize by accident.
- auto tableView = static_cast<QQuickTableView *>(parentItem()->parent());
- return !tableView->isMoving();
-}
-
void QQuickTableViewResizeHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
{
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
+ const auto *activeHandler = tableViewPrivate->activePointerHandler();
+ if (activeHandler && !qobject_cast<const QQuickTableViewResizeHandler *>(activeHandler))
+ return;
+
// Resolve which state we're in first...
updateState(point);
// ...and act on it next
@@ -6835,6 +7104,7 @@ void QQuickTableViewResizeHandler::updateDrag(QPointerEvent *event, QEventPoint
// pointer handlers to do flicking, so setting an exclusive grab (together
// with grab permissions) doens't work ATM.
tableView->setFiltersChildMouseEvents(false);
+ tableViewPrivate->setActivePointerHandler(this);
break;
case DraggingStarted:
setExclusiveGrab(event, point, true);
@@ -6856,6 +7126,7 @@ void QQuickTableViewResizeHandler::updateDrag(QPointerEvent *event, QEventPoint
break; }
case DraggingFinished: {
tableView->setFiltersChildMouseEvents(true);
+ tableViewPrivate->setActivePointerHandler(nullptr);
#if QT_CONFIG(cursor)
tableViewPrivate->updateCursor();
#endif
@@ -6864,6 +7135,310 @@ void QQuickTableViewResizeHandler::updateDrag(QPointerEvent *event, QEventPoint
}
// ----------------------------------------------
+QQuickTableViewSectionDragHandler::QQuickTableViewSectionDragHandler(QQuickTableView *view)
+ : QQuickTableViewPointerHandler(view)
+{
+ setObjectName("tableViewDragHandler");
+}
+
+QQuickTableViewSectionDragHandler::~QQuickTableViewSectionDragHandler()
+{
+ resetDragData();
+}
+
+void QQuickTableViewSectionDragHandler::resetDragData()
+{
+ if (m_state != Listening) {
+ m_state = Listening;
+ resetSectionOverlay();
+ m_source = -1;
+ m_destination = -1;
+ if (m_grabResult.data())
+ m_grabResult.data()->disconnect();
+ if (!m_drag.isNull()) {
+ m_drag->disconnect();
+ delete m_drag;
+ }
+ if (!m_dropArea.isNull()) {
+ m_dropArea->disconnect();
+ delete m_dropArea;
+ }
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ tableView->setFiltersChildMouseEvents(true);
+ }
+}
+
+void QQuickTableViewSectionDragHandler::resetSectionOverlay()
+{
+ if (m_destination != -1) {
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
+ const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : m_destination;
+ const int column = (m_sectionOrientation == Qt::Horizontal) ? m_destination : 0;
+ tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column), false);
+ m_destination = -1;
+ }
+}
+
+void QQuickTableViewSectionDragHandler::grabSection()
+{
+ // Generate the transparent section image in pixmap
+ QPixmap pixmap(m_grabResult->image().size());
+ pixmap.fill(Qt::transparent);
+ QPainter painter(&pixmap);
+ painter.setOpacity(0.6);
+ painter.drawImage(0, 0, m_grabResult->image());
+ painter.end();
+
+ // Specify the pixmap and mime data to be as drag object
+ auto *mimeData = new QMimeData();
+ mimeData->setImageData(pixmap);
+ m_drag->setMimeData(mimeData);
+ m_drag->setPixmap(pixmap);
+}
+
+void QQuickTableViewSectionDragHandler::handleDrop(QQuickDragEvent *event)
+{
+ Q_UNUSED(event);
+
+ if (m_state == Dragging) {
+ event->setAccepted(true);
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
+ tableViewPrivate->moveSection(m_source, m_destination, m_sectionOrientation);
+ m_state = DraggingFinished;
+ resetSectionOverlay();
+ if (m_scrollTimer.isActive())
+ m_scrollTimer.stop();
+ }
+}
+
+void QQuickTableViewSectionDragHandler::handleDrag(QQuickDragEvent *event)
+{
+ Q_UNUSED(event);
+
+ if (m_state == Dragging) {
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ const QPoint dragItemPosition(tableView->contentX() + event->x(), tableView->contentY() + event->y());
+ const auto *sourceItem = qobject_cast<QQuickItem *>(m_drag->source());
+ const QPoint targetCell = tableView->cellAtPosition(dragItemPosition, true);
+
+ auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
+ const int newDestination = (m_sectionOrientation == Qt::Horizontal) ? targetCell.x() : targetCell.y();
+ if (newDestination != m_destination) {
+ // Reset the overlay property in the existing model delegate item
+ resetSectionOverlay();
+ // Set the overlay property in the new model delegate item
+ const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : newDestination;
+ const int column = (m_sectionOrientation == Qt::Horizontal) ? newDestination : 0;
+ tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column), true);
+ m_destination = newDestination;
+ }
+
+ // Scroll header view while section item moves out of the table boundary
+ const QPoint dragItemStartPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() - sourceItem->width() / 2, dragItemPosition.y()) :
+ QPoint(dragItemPosition.x(), dragItemPosition.y() - sourceItem->height() / 2);
+ const QPoint dragItemEndPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() + sourceItem->width() / 2, dragItemPosition.y()) :
+ QPoint(dragItemPosition.x(), dragItemPosition.y() + sourceItem->height() / 2);
+ const bool useStartPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemStartPos.x() <= tableView->contentX()) : (dragItemStartPos.y() <= tableView->contentY());
+ const bool useEndPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemEndPos.x() >= tableView->width()) : (dragItemEndPos.y() >= tableView->height());
+ if (useStartPos || useEndPos) {
+ if (!m_scrollTimer.isActive()) {
+ m_dragPoint = (m_sectionOrientation == Qt::Horizontal) ? QPoint(useStartPos ? dragItemStartPos.x() : dragItemEndPos.x(), 0) :
+ QPoint(0, useStartPos ? dragItemStartPos.y() : dragItemEndPos.y());
+ m_scrollTimer.start(1);
+ }
+ } else {
+ if (m_scrollTimer.isActive())
+ m_scrollTimer.stop();
+ }
+ }
+}
+
+void QQuickTableViewSectionDragHandler::handleDragDropAction(Qt::DropAction action)
+{
+ // Reset the overlay property in the model delegate item when drag or drop
+ // happens outside specified drop area (i.e. during ignore action)
+ if (action == Qt::IgnoreAction) {
+ resetSectionOverlay();
+ if (m_scrollTimer.isActive())
+ m_scrollTimer.stop();
+ }
+}
+
+void QQuickTableViewSectionDragHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
+{
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
+ const auto *activeHandler = tableViewPrivate->activePointerHandler();
+ if (activeHandler && !qobject_cast<const QQuickTableViewSectionDragHandler *>(activeHandler))
+ return;
+
+ if (m_state == DraggingFinished)
+ resetDragData();
+
+ if (point.state() == QEventPoint::Pressed) {
+ // Reset the information in the drag handler
+ resetDragData();
+ // Activate the passive grab to get further move updates
+ setPassiveGrab(event, point, true);
+ // Disable flicking while dragging. TableView uses filtering instead of
+ // pointer handlers to do flicking, so setting an exclusive grab (together
+ // with grab permissions) doens't work ATM.
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ tableView->setFiltersChildMouseEvents(false);
+ m_state = Tracking;
+ } else if (point.state() == QEventPoint::Released) {
+ // Reset the information in the drag handler
+ resetDragData();
+ } else if (point.state() == QEventPoint::Updated) {
+ // Check to see that the movement can be considered as dragging
+ const qreal distX = point.position().x() - point.pressPosition().x();
+ const qreal distY = point.position().y() - point.pressPosition().y();
+ const qreal dragDist = qSqrt(distX * distX + distY * distY);
+ if (dragDist > qApp->styleHints()->startDragDistance()) {
+ switch (m_state) {
+ case Tracking: {
+ // Grab the image for dragging header
+ const QPoint cell = tableView->cellAtPosition(point.position(), true);
+ auto *item = tableView->itemAtCell(cell);
+ if (m_drag.isNull()) {
+ m_drag = new QDrag(item);
+ connect(m_drag.data(), &QDrag::actionChanged, this,
+ &QQuickTableViewSectionDragHandler::handleDragDropAction);
+ }
+ // Connect the timer for scroling
+ QObject::connect(&m_scrollTimer, &QTimer::timeout, [&]{
+ const QSizeF dist = tableViewPrivate->scrollTowardsPoint(m_dragPoint, m_step);
+ m_dragPoint.rx() += dist.width() > 0 ? m_step.width() : -m_step.width();
+ m_dragPoint.ry() += dist.height() > 0 ? m_step.height() : -m_step.height();
+ m_step = QSizeF(qAbs(dist.width() * 0.010), qAbs(dist.height() * 0.010));
+ });
+ // Set the drop area
+ if (m_dropArea.isNull()) {
+ m_dropArea = new QQuickDropArea(tableView);
+ m_dropArea->setSize(tableView->size());
+ connect(m_dropArea, &QQuickDropArea::positionChanged, this,
+ &QQuickTableViewSectionDragHandler::handleDrag);
+ connect(m_dropArea, &QQuickDropArea::dropped, this,
+ &QQuickTableViewSectionDragHandler::handleDrop);
+ }
+ // Grab the image of the section
+ m_grabResult = item->grabToImage();
+ connect(m_grabResult.data(), &QQuickItemGrabResult::ready, this,
+ &QQuickTableViewSectionDragHandler::grabSection);
+ // Update source depending on the type of orientation
+ m_source = (m_sectionOrientation == Qt::Horizontal) ? cell.x() : cell.y();
+ m_state = DraggingStarted;
+ // Set drag handler as active and it further handles section pointer events
+ tableViewPrivate->setActivePointerHandler(this);
+ }
+ break;
+
+ case DraggingStarted: {
+ if (m_drag && m_drag->mimeData()) {
+ if (auto *item = qobject_cast<QQuickItem *>(m_drag->source())) {
+ m_state = Dragging;
+ const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
+ Q_UNUSED(itemPos);
+ m_drag->setHotSpot(m_sectionOrientation == Qt::Horizontal ? QPoint(item->width()/2, itemPos.y()) : QPoint(itemPos.x(), item->height()/2));
+ m_drag->exec();
+ // Reset the active handler
+ tableViewPrivate->setActivePointerHandler(nullptr);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+// ----------------------------------------------
+void QQuickTableViewPrivate::initSectionDragHandler(Qt::Orientation orientation)
+{
+ if (!sectionDragHandler) {
+ Q_Q(QQuickTableView);
+ sectionDragHandler = new QQuickTableViewSectionDragHandler(q);
+ sectionDragHandler->setSectionOrientation(orientation);
+ }
+}
+
+void QQuickTableViewPrivate::destroySectionDragHandler()
+{
+ if (sectionDragHandler)
+ delete sectionDragHandler;
+}
+
+void QQuickTableViewPrivate::initializeIndexMapping()
+{
+ auto initIndices = [](auto& visualIndex, auto& logicalIndex, int size) {
+ visualIndex.resize(size);
+ logicalIndex.resize(size);
+ for (int index = 0; index < size; ++index)
+ visualIndex[index].index = logicalIndex[index].index = index;
+ };
+
+ if (!tableSize.isEmpty()) {
+ if (visualIndices[0].size() != tableSize.width()
+ || logicalIndices[0].size() != tableSize.width())
+ initIndices(visualIndices[0], logicalIndices[0], tableSize.width());
+
+ if (visualIndices[1].size() != tableSize.height()
+ || logicalIndices[1].size() != tableSize.height())
+ initIndices(visualIndices[1], logicalIndices[1], tableSize.height());
+ }
+}
+
+void QQuickTableViewPrivate::clearIndexMapping()
+{
+ logicalIndices[0].clear();
+ visualIndices[0].clear();
+
+ logicalIndices[1].clear();
+ visualIndices[1].clear();
+}
+
+int QQuickTableViewPrivate::logicalRowIndex(const int visualIndex) const
+{
+ if (syncView)
+ return syncView->d_func()->logicalRowIndex(visualIndex);
+ if (logicalIndices[1].isEmpty() || visualIndex < 0)
+ return visualIndex;
+ return logicalIndices[1].constData()[visualIndex].index;
+}
+
+int QQuickTableViewPrivate::logicalColumnIndex(const int visualIndex) const
+{
+ if (syncView)
+ return syncView->d_func()->logicalColumnIndex(visualIndex);
+ if (logicalIndices[0].isEmpty() || visualIndex < 0)
+ return visualIndex;
+ return logicalIndices[0].constData()[visualIndex].index;
+}
+
+int QQuickTableViewPrivate::visualRowIndex(const int logicalIndex) const
+{
+ if (syncView)
+ return syncView->d_func()->visualRowIndex(logicalIndex);
+ if (visualIndices[1].isEmpty() || logicalIndex < 0)
+ return logicalIndex;
+ return visualIndices[1].constData()[logicalIndex].index;
+}
+
+int QQuickTableViewPrivate::visualColumnIndex(const int logicalIndex) const
+{
+ if (syncView)
+ return syncView->d_func()->visualColumnIndex(logicalIndex);
+ if (visualIndices[0].isEmpty() || logicalIndex < 0)
+ return logicalIndex;
+ return visualIndices[0].constData()[logicalIndex].index;
+}
+
+// ----------------------------------------------
QQuickTableViewTapHandler::QQuickTableViewTapHandler(QQuickTableView *view)
: QQuickTapHandler(view->contentItem())
diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h
index cdde6de3d6..10cc53274d 100644
--- a/src/quick/items/qquicktableview_p.h
+++ b/src/quick/items/qquicktableview_p.h
@@ -233,6 +233,11 @@ public:
Q_INVOKABLE void positionViewAtCell(int column, int row, PositionMode mode, const QPointF &offset = QPointF(), const QRectF &subRect = QRectF());
#endif
+ Q_REVISION(6, 8) Q_INVOKABLE void moveColumn(int source, int destination);
+ Q_REVISION(6, 8) Q_INVOKABLE void moveRow(int source, int destination);
+ Q_REVISION(6, 8) Q_INVOKABLE void clearColumnReordering();
+ Q_REVISION(6, 8) Q_INVOKABLE void clearRowReordering();
+
static QQuickTableViewAttached *qmlAttachedProperties(QObject *);
Q_SIGNALS:
@@ -264,6 +269,9 @@ Q_SIGNALS:
Q_REVISION(6, 5) void editTriggersChanged();
Q_REVISION(6, 5) void layoutChanged();
Q_REVISION(6, 6) void selectionModeChanged();
+ Q_REVISION(6, 8) void rowMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
+ Q_REVISION(6, 8) void columnMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
+
protected:
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index 867e03485a..ea49a3309b 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -23,8 +23,8 @@
#include <QtQml/private/qqmlincubator_p.h>
#include <QtQmlModels/private/qqmlchangeset_p.h>
#include <QtQml/qqmlinfo.h>
+#include <QtGui/qdrag.h>
-#include <QtQuick/private/qminimalflatset_p.h>
#include <QtQuick/private/qquickflickable_p_p.h>
#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
#include <QtQuick/private/qquickanimation_p.h>
@@ -32,6 +32,9 @@
#include <QtQuick/private/qquicksinglepointhandler_p.h>
#include <QtQuick/private/qquickhoverhandler_p.h>
#include <QtQuick/private/qquicktaphandler_p.h>
+#include <QtQuick/private/qquickdroparea_p.h>
+
+#include <QtCore/private/qminimalflatset_p.h>
QT_BEGIN_NAMESPACE
@@ -67,15 +70,10 @@ protected:
void handleEventPoint(QPointerEvent *event, QEventPoint &point) override;
};
-/*! \internal
- * TableView uses QQuickTableViewResizeHandler to enable the user to resize
- * rows and columns. By using a custom pointer handler, we can get away with
- * using a single pointer handler for the whole content item, rather than
- * e.g having to split it up into multiple items with drag handlers placed
- * between the cells.
- */
-class QQuickTableViewResizeHandler : public QQuickSinglePointHandler
+class QQuickTableViewPointerHandler : public QQuickSinglePointHandler
{
+ Q_OBJECT
+
public:
enum State {
Listening, // the pointer is not being pressed between the cells
@@ -85,12 +83,28 @@ public:
DraggingFinished // dragging was finished
};
- QQuickTableViewResizeHandler(QQuickTableView *view);
- State state() { return m_state; }
- void updateState(QEventPoint &point);
- void updateDrag(QPointerEvent *event, QEventPoint &point);
+ QQuickTableViewPointerHandler(QQuickTableView *view);
State m_state = Listening;
+ State state() { return m_state; }
+
+protected:
+ bool wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) override;
+};
+
+/*! \internal
+ * TableView uses QQuickTableViewResizeHandler to enable the user to resize
+ * rows and columns. By using a custom pointer handler, we can get away with
+ * using a single pointer handler for the whole content item, rather than
+ * e.g having to split it up into multiple items with drag handlers placed
+ * between the cells.
+ */
+class QQuickTableViewResizeHandler : public QQuickTableViewPointerHandler
+{
+ Q_OBJECT
+
+public:
+ QQuickTableViewResizeHandler(QQuickTableView *view);
int m_row = -1;
qreal m_rowStartY = -1;
@@ -100,15 +114,54 @@ public:
qreal m_columnStartX = -1;
qreal m_columnStartWidth = -1;
+ void updateState(QEventPoint &point);
+ void updateDrag(QPointerEvent *event, QEventPoint &point);
+
friend class QQuickTableViewPrivate;
protected:
- bool wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) override;
void handleEventPoint(QPointerEvent *event, QEventPoint &point) override;
void onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition,
QPointerEvent *ev, QEventPoint &point) override;
};
+class QQuickTableViewSectionDragHandler : public QQuickTableViewPointerHandler
+{
+ Q_OBJECT
+
+public:
+ QQuickTableViewSectionDragHandler(QQuickTableView *view);
+ ~QQuickTableViewSectionDragHandler();
+
+ void grabSection();
+
+ void handleDrag(QQuickDragEvent *event);
+ void handleDrop(QQuickDragEvent *event);
+ void handleDragDropAction(Qt::DropAction action);
+
+ void setSectionOrientation(Qt::Orientation orientation) { m_sectionOrientation = orientation; }
+
+ friend class QQuickTableViewPrivate;
+
+protected:
+ void handleEventPoint(QPointerEvent *event, QEventPoint &point) override;
+
+private:
+ void resetDragData();
+ void resetSectionOverlay();
+
+ QSharedPointer<QQuickItemGrabResult> m_grabResult;
+ QPointer<QDrag> m_drag;
+ int m_source = -1;
+ int m_destination = -1;
+ QPointer<QQuickDropArea> m_dropArea;
+ Qt::Orientation m_sectionOrientation;
+
+ QPointF m_dragPoint;
+ QSizeF m_step = QSizeF(1, 1);
+ QTimer m_scrollTimer;
+};
+
/*! \internal
* QQuickTableViewTapHandler used to handle tap events explicitly for table view
*/
@@ -123,7 +176,6 @@ public:
friend class QQuickTableViewPrivate;
};
-
class Q_QUICK_EXPORT QQuickTableViewPrivate : public QQuickFlickablePrivate, public QQuickSelectable
{
public:
@@ -240,6 +292,11 @@ public:
Done
};
+ enum class SectionState {
+ Idle = 0,
+ Moving
+ };
+
enum class RebuildOption {
None = 0,
All = 0x1,
@@ -393,6 +450,8 @@ public:
QQuickTableViewHoverHandler *hoverHandler = nullptr;
QQuickTableViewResizeHandler *resizeHandler = nullptr;
+ QQuickTableViewSectionDragHandler *sectionDragHandler = nullptr;
+ QQuickTableViewPointerHandler *activePtrHandler = nullptr;
QQmlTableInstanceModel *editModel = nullptr;
QQuickItem *editItem = nullptr;
@@ -403,6 +462,16 @@ public:
QString forcedIncubationMode = qEnvironmentVariable("QT_TABLEVIEW_INCUBATION_MODE");
#endif
+ struct SectionData {
+ int index = -1;
+ int prevIndex = -1;
+ };
+
+ QList<SectionData> visualIndices[Qt::Vertical];
+ QList<SectionData> logicalIndices[Qt::Vertical];
+
+ SectionState m_sectionState = SectionState::Idle;
+
public:
void init();
@@ -410,7 +479,7 @@ public:
int modelIndexAtCell(const QPoint &cell) const;
QPoint cellAtModelIndex(int modelIndex) const;
- int modelIndexToCellIndex(const QModelIndex &modelIndex) const;
+ int modelIndexToCellIndex(const QModelIndex &modelIndex, bool visualIndex = true) const;
inline bool cellIsValid(const QPoint &cell) const { return cell.x() != -1 && cell.y() != -1; }
qreal sizeHintForColumn(int column) const;
@@ -589,7 +658,7 @@ public:
void clearSelection() override;
void normalizeSelection() override;
QRectF selectionRectangle() const override;
- QSizeF scrollTowardsSelectionPoint(const QPointF &pos, const QSizeF &step) override;
+ QSizeF scrollTowardsPoint(const QPointF &pos, const QSizeF &step) override;
void setCallback(std::function<void(CallBackFlag)> func) override;
void cancelSelectionTracking();
@@ -597,6 +666,22 @@ public:
virtual void updateSelection(const QRect &oldSelection, const QRect &newSelection);
QRect selection() const;
// ----------------
+
+ // Section drag handler
+ void initSectionDragHandler(Qt::Orientation orientation);
+ void destroySectionDragHandler();
+ inline void setActivePointerHandler(QQuickTableViewPointerHandler *handler) { activePtrHandler = handler; }
+ inline QQuickTableViewPointerHandler* activePointerHandler() const { return activePtrHandler; }
+ // Row/Column reordering
+ void moveSection(int source , int destination, Qt::Orientations orientation);
+ void initializeIndexMapping();
+ void clearIndexMapping();
+ void clearSection(Qt::Orientations orientation);
+ virtual int logicalRowIndex(const int visualIndex) const;
+ virtual int logicalColumnIndex(const int visualIndex) const;
+ virtual int visualRowIndex(const int logicalIndex) const;
+ virtual int visualColumnIndex(const int logicalIndex) const;
+ void setContainsDragOnDelegateItem(const QModelIndex &modelIndex, bool overlay);
};
class FxTableItem : public QQuickItemViewFxItem
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 3b37dd975b..f918a0da2e 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -11,7 +11,6 @@
#include <private/qqmlglobal_p.h>
#include <private/qsgadaptationlayer_p.h>
#include "qsginternaltextnode_p.h"
-#include "qquickimage_p_p.h"
#include "qquicktextutil_p.h"
#include <QtQuick/private/qsgtexture_p.h>
@@ -49,7 +48,7 @@ const QChar QQuickTextPrivate::elideChar = QChar(0x2026);
const int QQuickTextPrivate::largeTextSizeThreshold = QQUICKTEXT_LARGETEXT_THRESHOLD;
QQuickTextPrivate::QQuickTextPrivate()
- : fontInfo(font), elideLayout(nullptr), textLine(nullptr), lineWidth(0)
+ : fontInfo(font), lineWidth(0)
, color(0xFF000000), linkColor(0xFF0000FF), styleColor(0xFF000000)
, lineCount(1), multilengthEos(-1)
, elideMode(QQuickText::ElideNone), hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop)
@@ -82,7 +81,6 @@ QQuickTextPrivate::ExtraData::ExtraData()
, doc(nullptr)
, minimumPixelSize(12)
, minimumPointSize(12)
- , nbActiveDownloads(0)
, maximumLineCount(INT_MAX)
, renderTypeQuality(QQuickText::DefaultRenderTypeQuality)
, lineHeightValid(false)
@@ -101,9 +99,6 @@ void QQuickTextPrivate::init()
QQuickTextPrivate::~QQuickTextPrivate()
{
- delete elideLayout;
- delete textLine; textLine = nullptr;
-
if (extra.isAllocated()) {
qDeleteAll(extra->imgTags);
extra->imgTags.clear();
@@ -357,29 +352,33 @@ void QQuickText::resourceRequestFinished()
void QQuickText::imageDownloadFinished()
{
Q_D(QQuickText);
+ if (!d->extra.isAllocated())
+ return;
- (d->extra->nbActiveDownloads)--;
+ if (std::any_of(d->extra->imgTags.cbegin(), d->extra->imgTags.cend(),
+ [] (auto *image) { return image->pix && image->pix->isLoading(); })) {
+ // return if we still have any active download
+ return;
+ }
// when all the remote images have been downloaded,
// if one of the sizes was not specified at parsing time
// we use the implicit size from pixmapcache and re-layout.
- if (d->extra.isAllocated() && d->extra->nbActiveDownloads == 0) {
- bool needToUpdateLayout = false;
- for (QQuickStyledTextImgTag *img : std::as_const(d->extra->visibleImgTags)) {
- if (!img->size.isValid()) {
- img->size = img->pix->implicitSize();
- needToUpdateLayout = true;
- }
+ bool needToUpdateLayout = false;
+ for (QQuickStyledTextImgTag *img : std::as_const(d->extra->visibleImgTags)) {
+ if (!img->size.isValid()) {
+ img->size = img->pix->implicitSize();
+ needToUpdateLayout = true;
}
+ }
- if (needToUpdateLayout) {
- d->textHasChanged = true;
- d->updateLayout();
- } else {
- d->updateType = QQuickTextPrivate::UpdatePaintNode;
- update();
- }
+ if (needToUpdateLayout) {
+ d->textHasChanged = true;
+ d->updateLayout();
+ } else {
+ d->updateType = QQuickTextPrivate::UpdatePaintNode;
+ update();
}
}
@@ -677,7 +676,7 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height,
Q_Q(QQuickText);
if (!textLine)
- textLine = new QQuickTextLine;
+ textLine.reset(new QQuickTextLine);
textLine->setFullLayoutTextLength(fullLayoutTextLength);
textLine->setLine(&line);
textLine->setY(height);
@@ -693,7 +692,7 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height,
if (lineHeight() != 1.0)
textLine->setHeight((lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : line.height() * lineHeight());
- emit q->lineLaidOut(textLine);
+ emit q->lineLaidOut(textLine.get());
height += textLine->height();
}
@@ -1189,7 +1188,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
if (elide) {
if (!elideLayout) {
- elideLayout = new QTextLayout;
+ elideLayout.reset(new QTextLayout);
elideLayout->setCacheEnabled(true);
}
QTextEngine *engine = layout.engine();
@@ -1239,8 +1238,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
if (visibleCount == 1)
layout.clearLayout();
} else {
- delete elideLayout;
- elideLayout = nullptr;
+ elideLayout.reset();
}
QTextLine firstLine = visibleCount == 1 && elideLayout
@@ -1289,12 +1287,10 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal
if (!image->pix) {
const QQmlContext *context = qmlContext(q);
const QUrl url = context->resolvedUrl(q->baseUrl()).resolved(image->url);
- image->pix = new QQuickPixmap(context->engine(), url, QRect(), image->size);
+ image->pix.reset(new QQuickPixmap(context->engine(), url, QRect(), image->size * devicePixelRatio()));
+
if (image->pix->isLoading()) {
image->pix->connectFinished(q, SLOT(imageDownloadFinished()));
- if (!extra.isAllocated() || !extra->nbActiveDownloads)
- extra.value().nbActiveDownloads = 0;
- extra->nbActiveDownloads++;
} else if (image->pix->isReady()) {
if (!image->size.isValid()) {
image->size = image->pix->implicitSize();
@@ -1379,6 +1375,11 @@ void QQuickTextPrivate::updateDocumentText()
rightToLeftText = extra->doc->toPlainText().isRightToLeft();
}
+qreal QQuickTextPrivate::devicePixelRatio() const
+{
+ return (window ? window->effectiveDevicePixelRatio() : qApp->devicePixelRatio());
+}
+
/*!
\qmltype Text
\instantiates QQuickText
@@ -1847,6 +1848,53 @@ QQuickText::~QQuickText()
\sa QFont::setFeature()
//! [qml-font-features]
*/
+
+/*!
+ \qmlproperty bool QtQuick::Text::font.contextFontMerging
+ \since 6.8
+
+//! [qml-font-context-font-merging]
+ If the selected font does not contain a certain character, Qt automatically chooses a
+ similar-looking fallback font that contains the character. By default this is done on a
+ character-by-character basis.
+
+ This means that in certain uncommon cases, many different fonts may be used to represent one
+ string of text even if it's in the same script. Setting \c contextFontMerging to true will try
+ finding the fallback font that matches the largest subset of the input string instead. This
+ will be more expensive for strings where missing glyphs occur, but may give more consistent
+ results. By default, \c contextFontMerging is \c{false}.
+
+ \sa QFont::StyleStrategy
+//! [qml-font-context-font-merging]
+*/
+
+/*!
+ \qmlproperty bool QtQuick::Text::font.preferTypoLineMetrics
+ \since 6.8
+
+//! [qml-font-prefer-typo-line-metrics] For compatibility reasons, OpenType fonts contain two
+ competing sets of the vertical line metrics that provide the \l{QFontMetricsF::ascent()}{ascent},
+ \l{QFontMetricsF::descent()}{descent} and \l{QFontMetricsF::leading()}{leading} of the font. These
+ are often referred to as the
+ \l{https://learn.microsoft.com/en-us/typography/opentype/spec/os2#uswinascent}{win} (Windows)
+ metrics and the \l{https://learn.microsoft.com/en-us/typography/opentype/spec/os2#sta}{typo}
+ (typographical) metrics. While the specification recommends using the \c typo metrics for line
+ spacing, many applications prefer the \c win metrics unless the \c{USE_TYPO_METRICS} flag is set in
+ the \l{https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fsselection}{fsSelection}
+ field of the font. For backwards-compatibility reasons, this is also the case for Qt applications.
+ This is not an issue for fonts that set the \c{USE_TYPO_METRICS} flag to indicate that the \c{typo}
+ metrics are valid, nor for fonts where the \c{win} metrics and \c{typo} metrics match up. However,
+ for certain fonts the \c{win} metrics may be larger than the preferable line spacing and the
+ \c{USE_TYPO_METRICS} flag may be unset by mistake. For such fonts, setting
+ \c{font.preferTypoLineMetrics} may give superior results.
+
+ By default, \c preferTypoLineMetrics is \c{false}.
+
+ \sa QFont::StyleStrategy
+//! [qml-font-prefer-typo-line-metrics]
+*/
+
+
QFont QQuickText::font() const
{
Q_D(const QQuickText);
@@ -1901,14 +1949,30 @@ void QQuickText::itemChange(ItemChange change, const ItemChangeData &value)
break;
case ItemDevicePixelRatioHasChanged:
- if (d->renderType == NativeRendering) {
- // Native rendering optimizes for a given pixel grid, so its results must not be scaled.
- // Text layout code respects the current device pixel ratio automatically, we only need
- // to rerun layout after the ratio changed.
- // Changes of implicit size should be minimal; they are hard to avoid.
- d->implicitWidthValid = false;
- d->implicitHeightValid = false;
- d->updateLayout();
+ {
+ bool needUpdateLayout = false;
+ if (d->renderType == NativeRendering) {
+ // Native rendering optimizes for a given pixel grid, so its results must not be scaled.
+ // Text layout code respects the current device pixel ratio automatically, we only need
+ // to rerun layout after the ratio changed.
+ // Changes of implicit size should be minimal; they are hard to avoid.
+ d->implicitWidthValid = false;
+ d->implicitHeightValid = false;
+ needUpdateLayout = true;
+ }
+
+ if (d->extra.isAllocated()) {
+ // check if we have scalable inline images with explicit size set, which should be reloaded
+ for (QQuickStyledTextImgTag *image : std::as_const(d->extra->visibleImgTags)) {
+ if (image->size.isValid() && QQuickPixmap::isScalableImageFormat(image->url)) {
+ image->pix.reset();
+ needUpdateLayout = true;
+ }
+ }
+ }
+
+ if (needUpdateLayout)
+ d->updateLayout();
}
break;
@@ -2749,13 +2813,12 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
node->addTextLayout(QPointF(dx, dy), &d->layout, -1, -1,0, unelidedLineCount);
if (d->elideLayout)
- node->addTextLayout(QPointF(dx, dy), d->elideLayout);
+ node->addTextLayout(QPointF(dx, dy), d->elideLayout.get());
if (d->extra.isAllocated()) {
for (QQuickStyledTextImgTag *img : std::as_const(d->extra->visibleImgTags)) {
- QQuickPixmap *pix = img->pix;
- if (pix && pix->isReady())
- node->addImage(QRectF(img->pos.x() + dx, img->pos.y() + dy, pix->width(), pix->height()), pix->image());
+ if (img->pix && img->pix->isReady())
+ node->addImage(QRectF(img->pos.x() + dx, img->pos.y() + dy, img->size.width(), img->size.height()), img->pix->image());
}
}
}
@@ -3042,7 +3105,7 @@ QString QQuickTextPrivate::anchorAt(const QPointF &mousePos) const
if (styledText) {
QString link = anchorAt(&layout, translatedMousePos);
if (link.isEmpty() && elideLayout)
- link = anchorAt(elideLayout, translatedMousePos);
+ link = anchorAt(elideLayout.get(), translatedMousePos);
return link;
} else if (richText && extra.isAllocated() && extra->doc) {
translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), availableWidth(), q->effectiveHAlign());
diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h
index 2e54ae53a1..6dba7a7d75 100644
--- a/src/quick/items/qquicktext_p_p.h
+++ b/src/quick/items/qquicktext_p_p.h
@@ -77,7 +77,6 @@ public:
QString hoveredLink;
int minimumPixelSize;
int minimumPointSize;
- int nbActiveDownloads;
int maximumLineCount;
int renderTypeQuality;
bool lineHeightValid : 1;
@@ -96,8 +95,8 @@ public:
QFontInfo fontInfo;
QTextLayout layout;
- QTextLayout *elideLayout;
- QQuickTextLine *textLine;
+ QScopedPointer<QTextLayout> elideLayout;
+ QScopedPointer<QQuickTextLine> textLine;
qreal lineWidth;
@@ -164,6 +163,8 @@ public:
void ensureDoc();
void updateDocumentText();
+ qreal devicePixelRatio() const;
+
QRectF setupTextLayout(qreal * const baseline);
void setupCustomLineGeometry(QTextLine &line, qreal &height, int fullLayoutTextLength, int lineOffset = 0);
bool isLinkActivatedConnected();
diff --git a/src/quick/items/qquicktextdocument.cpp b/src/quick/items/qquicktextdocument.cpp
index 6443b9ef70..a1fb7adcea 100644
--- a/src/quick/items/qquicktextdocument.cpp
+++ b/src/quick/items/qquicktextdocument.cpp
@@ -326,13 +326,15 @@ void QQuickTextDocumentPrivate::load()
setStatus(QQuickTextDocument::Status::Loading, {});
QByteArray data = file.readAll();
doc->setBaseUrl(resolvedUrl.adjusted(QUrl::RemoveFilename));
+#if QT_CONFIG(textmarkdownreader) || QT_CONFIG(texthtmlparser)
const bool plainText = editor->textFormat() == QQuickTextEdit::PlainText;
+#endif
#if QT_CONFIG(textmarkdownreader)
if (!plainText && isMarkdown) {
doc->setMarkdown(QString::fromUtf8(data));
} else
#endif
-#ifndef QT_NO_TEXTHTMLPARSER
+#if QT_CONFIG(texthtmlparser)
if (!plainText && isHtml) {
// If a user loads an HTML file, remember the encoding.
// If the user then calls save() later, the same encoding will be used.
@@ -411,7 +413,7 @@ void QQuickTextDocumentPrivate::writeTo(const QUrl &fileUrl)
raw = doc->toMarkdown().toUtf8();
break;
#endif
-#ifndef QT_NO_TEXTHTMLPARSER
+#if QT_CONFIG(texthtmlparser)
case Qt::RichText:
if (sameUrl && encoding) {
QStringEncoder enc(*encoding);
@@ -587,10 +589,24 @@ QSizeF QQuickTextImageHandler::intrinsicSize(
{
if (format.isImageFormat()) {
QTextImageFormat imageFormat = format.toImageFormat();
- const int width = qRound(imageFormat.width());
+ int width = qRound(imageFormat.width());
const bool hasWidth = imageFormat.hasProperty(QTextFormat::ImageWidth) && width > 0;
const int height = qRound(imageFormat.height());
const bool hasHeight = imageFormat.hasProperty(QTextFormat::ImageHeight) && height > 0;
+ const auto maxWidth = imageFormat.maximumWidth();
+ const bool hasMaxWidth = imageFormat.hasProperty(QTextFormat::ImageMaxWidth) && maxWidth.type() != QTextLength::VariableLength;
+
+ int effectiveMaxWidth = INT_MAX;
+ if (hasMaxWidth) {
+ if (maxWidth.type() == QTextLength::PercentageLength) {
+ effectiveMaxWidth = (doc->pageSize().width() - 2 * doc->documentMargin()) * maxWidth.value(100) / 100;
+ } else {
+ effectiveMaxWidth = maxWidth.rawValue();
+ }
+
+ width = qMin(effectiveMaxWidth, width);
+ }
+
QSizeF size(width, height);
if (!hasWidth || !hasHeight) {
QVariant res = doc->resource(QTextDocument::ImageResource, QUrl(imageFormat.name()));
@@ -605,11 +621,17 @@ QSizeF QQuickTextImageHandler::intrinsicSize(
return size;
}
QSize imgSize = image.size();
+ if (imgSize.width() > effectiveMaxWidth) {
+ // image is bigger than effectiveMaxWidth, scale it down
+ imgSize.setHeight(effectiveMaxWidth * imgSize.height() / (qreal) imgSize.width());
+ imgSize.setWidth(effectiveMaxWidth);
+ }
+
if (!hasWidth) {
if (!hasHeight)
size.setWidth(imgSize.width());
else
- size.setWidth(qRound(height * (imgSize.width() / (qreal) imgSize.height())));
+ size.setWidth(qMin(effectiveMaxWidth, qRound(height * (imgSize.width() / (qreal) imgSize.height()))));
}
if (!hasHeight) {
if (!hasWidth)
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 22bbd6e05b..854c2e17fd 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -376,6 +376,20 @@ QString QQuickTextEdit::text() const
*/
/*!
+ \qmlproperty bool QtQuick::TextEdit::font.contextFontMerging
+ \since 6.8
+
+ \include qquicktext.cpp qml-font-context-font-merging
+*/
+
+/*!
+ \qmlproperty bool QtQuick::TextEdit::font.preferTypoLineMetrics
+ \since 6.8
+
+ \include qquicktext.cpp qml-font-prefer-typo-line-metrics
+*/
+
+/*!
\qmlproperty string QtQuick::TextEdit::text
The text to display. If the text format is AutoText the text edit will
@@ -862,6 +876,7 @@ void QQuickTextEdit::setHAlign(HAlignment align)
if (d->setHAlign(align, true) && isComponentComplete()) {
d->updateDefaultTextOption();
updateSize();
+ updateWholeDocument();
}
}
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index ef00451788..0826011a54 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -403,6 +403,20 @@ QString QQuickTextInputPrivate::realText() const
\include qquicktext.cpp qml-font-features
*/
+
+/*!
+ \qmlproperty bool QtQuick::TextInput::font.contextFontMerging
+ \since 6.8
+
+ \include qquicktext.cpp qml-font-context-font-merging
+*/
+
+/*!
+ \qmlproperty bool QtQuick::TextInput::font.preferTypoLineMetrics
+ \since 6.8
+
+ \include qquicktext.cpp qml-font-prefer-typo-line-metrics
+*/
QFont QQuickTextInput::font() const
{
Q_D(const QQuickTextInput);
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index fd33fa86e2..c486fece40 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -660,10 +660,14 @@ void QQuickTextNodeEngine::addFrameDecorations(QTextDocument *document, QTextFra
if (borderStyle == QTextFrameFormat::BorderStyle_None)
return;
- addBorder(boundingRect.adjusted(frameFormat.leftMargin(), frameFormat.topMargin(),
- -frameFormat.rightMargin() - borderWidth,
- -frameFormat.bottomMargin() - borderWidth),
- borderWidth, borderStyle, borderBrush);
+ const auto collapsed = table->format().borderCollapse();
+
+ if (!collapsed) {
+ addBorder(boundingRect.adjusted(frameFormat.leftMargin(), frameFormat.topMargin(),
+ -frameFormat.rightMargin() - borderWidth,
+ -frameFormat.bottomMargin() - borderWidth),
+ borderWidth, borderStyle, borderBrush);
+ }
if (table != nullptr) {
int rows = table->rows();
int columns = table->columns();
@@ -673,7 +677,7 @@ void QQuickTextNodeEngine::addFrameDecorations(QTextDocument *document, QTextFra
QTextTableCell cell = table->cellAt(row, column);
QRectF cellRect = documentLayout->tableCellBoundingRect(table, cell);
- addBorder(cellRect.adjusted(-borderWidth, -borderWidth, 0, 0), borderWidth,
+ addBorder(cellRect.adjusted(-borderWidth, -borderWidth, collapsed ? -borderWidth : 0, collapsed ? -borderWidth : 0), borderWidth,
borderStyle, borderBrush);
}
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index b8c7878e04..eb969e7476 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -956,6 +956,22 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
// The confirmExitPopup allows user to save or discard the document,
// or to cancel the closing.
\endcode
+
+ \section1 Styling
+
+ As with all visual types in Qt Quick, Window supports
+ \l {palette}{palettes}. However, as with types like \l Text, Window does
+ not use palettes by default. For example, to change the background color
+ of the window when the operating system's theme changes, the \l color must
+ be set:
+
+ \snippet qml/windowPalette.qml declaration-and-color
+ \codeline
+ \snippet qml/windowPalette.qml text-item
+ \snippet qml/windowPalette.qml closing-brace
+
+ Use \l {ApplicationWindow} (and \l {Label}) from \l {Qt Quick Controls}
+ instead of Window to get automatic styling.
*/
/*!
@@ -1853,6 +1869,41 @@ void QQuickWindowPrivate::clearFocusObject()
da->clearFocusObject();
}
+void QQuickWindowPrivate::setFocusToTarget(FocusTarget target, Qt::FocusReason reason)
+{
+ if (!contentItem)
+ return;
+
+ QQuickItem *newFocusItem = nullptr;
+ switch (target) {
+ case FocusTarget::First:
+ case FocusTarget::Last: {
+ const bool forward = (target == FocusTarget::First);
+ newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(contentItem, forward);
+ if (newFocusItem) {
+ const auto *itemPriv = QQuickItemPrivate::get(newFocusItem);
+ if (itemPriv->subFocusItem && itemPriv->flags & QQuickItem::ItemIsFocusScope)
+ clearFocusInScope(newFocusItem, itemPriv->subFocusItem, reason);
+ }
+ break;
+ }
+ case FocusTarget::Next:
+ case FocusTarget::Prev: {
+ const auto da = deliveryAgentPrivate();
+ Q_ASSERT(da);
+ QQuickItem *focusItem = da->focusTargetItem() ? da->focusTargetItem() : contentItem;
+ bool forward = (target == FocusTarget::Next);
+ newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(focusItem, forward);
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (newFocusItem)
+ newFocusItem->forceActiveFocus(reason);
+}
+
/*!
\qmlproperty list<QtObject> Window::data
\qmldefault
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 1b1b12de65..8ba4e56515 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -146,6 +146,7 @@ public:
#endif
void clearFocusObject() override;
+ void setFocusToTarget(FocusTarget, Qt::FocusReason) override;
void dirtyItem(QQuickItem *);
void cleanup(QSGNode *);
diff --git a/src/quick/items/qquickwindowcontainer.cpp b/src/quick/items/qquickwindowcontainer.cpp
index 839a30330d..55806356f6 100644
--- a/src/quick/items/qquickwindowcontainer.cpp
+++ b/src/quick/items/qquickwindowcontainer.cpp
@@ -21,7 +21,6 @@ using namespace Qt::StringLiterals;
\inqmlmodule QtQuick
\ingroup qtquick-visual
\inherits Item
- \instantiates QQuickItem
\since 6.7
\preliminary
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index c4a978dec8..e539880452 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -35,7 +35,15 @@ QQuickWindowQmlImpl::QQuickWindowQmlImpl(QQuickWindowQmlImplPrivate &dd, QWindow
: QQuickWindow(dd, parent)
{
connect(this, &QWindow::visibleChanged, this, &QQuickWindowQmlImpl::visibleChanged);
- connect(this, &QWindow::visibilityChanged, this, &QQuickWindowQmlImpl::visibilityChanged);
+ connect(this, &QWindow::visibilityChanged, this, [&]{
+ Q_D(QQuickWindowQmlImpl);
+ // Update the window's actual visibility and turn off visibilityExplicitlySet,
+ // so that future applyWindowVisibility() calls do not apply both window state
+ // and visible state, unless setVisibility() is called again by the user.
+ d->visibility = QWindow::visibility();
+ d->visibilityExplicitlySet = false;
+ emit QQuickWindowQmlImpl::visibilityChanged(d->visibility);
+ });
connect(this, &QWindow::screenChanged, this, &QQuickWindowQmlImpl::screenChanged);
// We shadow the x and y properties, so that we can re-map them in case
@@ -110,6 +118,7 @@ void QQuickWindowQmlImpl::setVisibility(Visibility visibility)
{
Q_D(QQuickWindowQmlImpl);
d->visibility = visibility;
+ d->visibilityExplicitlySet = true;
if (d->componentComplete)
applyWindowVisibility();
}
@@ -190,8 +199,8 @@ void QQuickWindowQmlImpl::applyWindowVisibility()
Q_ASSERT(d->componentComplete);
- const bool visible = d->visibility == AutomaticVisibility
- ? d->visible : d->visibility != Hidden;
+ const bool visible = d->visibilityExplicitlySet
+ ? d->visibility != Hidden : d->visible;
qCDebug(lcQuickWindow) << "Applying visible" << visible << "for" << this;
@@ -234,20 +243,30 @@ void QQuickWindowQmlImpl::applyWindowVisibility()
}
}
- if (d->visibleExplicitlySet && ((d->visibility == Hidden && d->visible) ||
- (d->visibility > AutomaticVisibility && !d->visible))) {
+ if (d->visibleExplicitlySet && d->visibilityExplicitlySet &&
+ ((d->visibility == Hidden && d->visible) ||
+ (d->visibility > AutomaticVisibility && !d->visible))) {
// FIXME: Should we bail out in this case?
qmlWarning(this) << "Conflicting properties 'visible' and 'visibility'";
}
if (d->visibility == AutomaticVisibility) {
+ // We're either showing for the first time, with the default
+ // visibility of AutomaticVisibility, or the user has called
+ // setVisibility with AutomaticVisibility at some point, so
+ // apply both window state and visible.
if (QWindow::parent() || visualParent())
setWindowState(Qt::WindowNoState);
else
setWindowState(QGuiApplicationPrivate::platformIntegration()->defaultWindowState(flags()));
QQuickWindow::setVisible(d->visible);
- } else {
+ } else if (d->visibilityExplicitlySet) {
+ // We're not AutomaticVisibility, but the user has requested
+ // an explicit visibility, so apply both window state and visible.
QQuickWindow::setVisibility(d->visibility);
+ } else {
+ // Our window state should be up to date, so only apply visible
+ QQuickWindow::setVisible(d->visible);
}
}
diff --git a/src/quick/items/qquickwindowmodule_p_p.h b/src/quick/items/qquickwindowmodule_p_p.h
index bda666e15b..227b8aa01e 100644
--- a/src/quick/items/qquickwindowmodule_p_p.h
+++ b/src/quick/items/qquickwindowmodule_p_p.h
@@ -30,6 +30,8 @@ public:
bool visible = false;
bool visibleExplicitlySet = false;
QQuickWindow::Visibility visibility = QQuickWindow::AutomaticVisibility;
+ bool visibilityExplicitlySet = false;
+
QV4::PersistentValue rootItemMarker;
QMetaObject::Connection itemParentWindowChangeListener;
diff --git a/src/quick/jar/CMakeLists.txt b/src/quick/jar/CMakeLists.txt
index 9555bbca16..f6014b2d55 100644
--- a/src/quick/jar/CMakeLists.txt
+++ b/src/quick/jar/CMakeLists.txt
@@ -2,7 +2,16 @@ qt_internal_add_jar(Qt${QtDeclarative_VERSION_MAJOR}AndroidQuick
INCLUDE_JARS
${QT_ANDROID_JAR}
${QT6_INSTALL_PREFIX}/jar/Qt${QtDeclarative_VERSION_MAJOR}Android.jar
- SOURCES org/qtproject/qt/android/QtQuickView.java
+ SOURCES
+ org/qtproject/qt/android/QtQuickView.java
+ org/qtproject/qt/android/QtSignalListener.java
+ org/qtproject/qt/android/QtQmlStatus.java
+ org/qtproject/qt/android/QtQmlStatusChangeListener.java
+ org/qtproject/qt/android/QtModelIndex.java
+ org/qtproject/qt/android/QtAbstractItemModel.java
+ org/qtproject/qt/android/QtAbstractItemModelProxy.java
+ org/qtproject/qt/android/QtQmlComponent.java
+ org/qtproject/qt/android/QtAbstractListModel.java
OUTPUT_DIR "${QT_BUILD_DIR}/jar")
qt_path_join(destination ${INSTALL_DATADIR} "jar")
diff --git a/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModel.java b/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModel.java
new file mode 100644
index 0000000000..40c635235f
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModel.java
@@ -0,0 +1,105 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import java.util.HashMap;
+
+public abstract class QtAbstractItemModel
+{
+ public QtAbstractItemModel(){};
+ public abstract int columnCount(QtModelIndex parent);
+ public abstract Object data(QtModelIndex index, int role);
+ public abstract QtModelIndex index(int row, int column, QtModelIndex parent);
+ public abstract QtModelIndex parent(QtModelIndex index);
+ public abstract int rowCount(QtModelIndex parent);
+
+ public native boolean canFetchMore(QtModelIndex parent);
+ public native void fetchMore(QtModelIndex parent);
+ public native boolean hasChildren(QtModelIndex parent);
+ public native boolean hasIndex(int row, int column, QtModelIndex parent);
+
+ public HashMap<Integer, String> roleNames()
+ {
+ return (HashMap<Integer, String>)jni_roleNames();
+ }
+
+ public QtModelIndex sibling(int row, int column, QtModelIndex parent)
+ {
+ return (QtModelIndex)jni_sibling(row, column, parent);
+ }
+
+ protected final void beginInsertColumns(QtModelIndex parent, int first, int last)
+ {
+ jni_beginInsertColumns(parent, first, last);
+ }
+
+ protected final void beginInsertRows(QtModelIndex parent, int first, int last)
+ {
+ jni_beginInsertRows(parent, first, last);
+ }
+ protected final boolean beginMoveColumns(QtModelIndex sourceParent, int sourceFirst,
+ int sourceLast, QtModelIndex destinationParent,
+ int destinationChild)
+ {
+ return jni_beginMoveColumns(sourceParent, sourceFirst, sourceLast, destinationParent,
+ destinationChild);
+ }
+ protected final boolean beginMoveRows(QtModelIndex sourceParent, int sourceFirst,
+ int sourceLast, QtModelIndex destinationParent,
+ int destinationChild)
+ {
+ return jni_beginMoveRows(sourceParent, sourceFirst, sourceLast, destinationParent,
+ destinationChild);
+ }
+ protected final void beginRemoveColumns(QtModelIndex parent, int first, int last)
+ {
+ jni_beginRemoveColumns(parent, first, last);
+ }
+ protected final void beginRemoveRows(QtModelIndex parent, int first, int last)
+ {
+ jni_beginRemoveRows(parent, first, last);
+ }
+ protected final void beginResetModel() { jni_beginResetModel(); }
+
+ protected final QtModelIndex createIndex(int row, int column, long id)
+ {
+ return (QtModelIndex)jni_createIndex(row, column, id);
+ }
+ protected final void endInsertColumns() { jni_endInsertColumns(); }
+ protected final void endInsertRows() { jni_endInsertRows(); }
+ protected final void endMoveColumns() { jni_endMoveColumns(); }
+ protected final void endMoveRows() { jni_endMoveRows(); }
+ protected final void endRemoveColumns() { jni_endRemoveColumns(); }
+ protected final void endRemoveRows() { jni_endRemoveRows(); }
+ protected final void endResetModel() { jni_endResetModel(); }
+
+ private native void jni_beginInsertColumns(QtModelIndex parent, int first, int last);
+ private native void jni_beginInsertRows(QtModelIndex parent, int first, int last);
+ private native boolean jni_beginMoveColumns(QtModelIndex sourceParent, int sourceFirst,
+ int sourceLast, QtModelIndex destinationParent,
+ int destinationChild);
+ private native boolean jni_beginMoveRows(QtModelIndex sourceParent, int sourceFirst,
+ int sourceLast, QtModelIndex destinationParent,
+ int destinationChild);
+ private native void jni_beginRemoveColumns(QtModelIndex parent, int first, int last);
+ private native void jni_beginRemoveRows(QtModelIndex parent, int first, int last);
+ private native void jni_beginResetModel();
+ private native Object jni_createIndex(int row, int column, long id);
+ private native void jni_endInsertColumns();
+ private native void jni_endInsertRows();
+ private native void jni_endMoveColumns();
+ private native void jni_endMoveRows();
+ private native void jni_endRemoveColumns();
+ private native void jni_endRemoveRows();
+ private native void jni_endResetModel();
+ private native Object jni_roleNames();
+ private native Object jni_sibling(int row, int column, QtModelIndex parent);
+
+ private long m_nativeReference = 0;
+ private QtAbstractItemModel(long nativeReference) { m_nativeReference = nativeReference; }
+ private void detachFromNative() { m_nativeReference = 0; };
+ private long nativeReference() { return m_nativeReference; }
+ private void setNativeReference(long nativeReference) { m_nativeReference = nativeReference; }
+ private static boolean instanceOf(Object obj) { return (obj instanceof QtAbstractItemModel); }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModelProxy.java b/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModelProxy.java
new file mode 100644
index 0000000000..6432a3e12e
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModelProxy.java
@@ -0,0 +1,35 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+class QtAndroidItemModelProxy extends QtAbstractItemModel
+{
+ @Override public int columnCount(QtModelIndex parent) { return jni_columnCount(parent); };
+ @Override public Object data(QtModelIndex index, int role) { return jni_data(index, role); }
+ @Override public QtModelIndex index(int row, int column, QtModelIndex parent)
+ {
+ return (QtModelIndex)jni_index(row, column, parent);
+ }
+ @Override public QtModelIndex parent(QtModelIndex index)
+ {
+ return (QtModelIndex)jni_parent(index);
+ }
+ @Override public int rowCount(QtModelIndex parent) { return jni_rowCount(parent); }
+
+ private native int jni_columnCount(QtModelIndex parent);
+ private native Object jni_data(QtModelIndex index, int role);
+ private native Object jni_index(int row, int column, QtModelIndex parent);
+ private native Object jni_parent(QtModelIndex index);
+ private native int jni_rowCount(QtModelIndex parent);
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtAbstractListModel.java b/src/quick/jar/org/qtproject/qt/android/QtAbstractListModel.java
new file mode 100644
index 0000000000..5a49caca9c
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtAbstractListModel.java
@@ -0,0 +1,30 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import java.util.HashMap;
+
+public abstract class QtAbstractListModel extends QtAbstractItemModel
+{
+ public QtAbstractListModel(){};
+
+ @Override public final int columnCount(QtModelIndex parent) { return parent.isValid() ? 0 : 1; }
+
+ @Override public QtModelIndex index(int row, int column, QtModelIndex parent)
+ {
+ return hasIndex(row, column, parent) ? createIndex(row, column, 0) : new QtModelIndex();
+ }
+
+ @Override public final QtModelIndex parent(QtModelIndex index) { return new QtModelIndex(); }
+
+ @Override public final boolean hasChildren(QtModelIndex parent)
+ {
+ return parent.isValid() ? false : (rowCount(new QtModelIndex()) > 0);
+ }
+
+ @Override public QtModelIndex sibling(int row, int column, QtModelIndex parent)
+ {
+ return index(row, column, new QtModelIndex());
+ }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtModelIndex.java b/src/quick/jar/org/qtproject/qt/android/QtModelIndex.java
new file mode 100644
index 0000000000..955c736ec4
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtModelIndex.java
@@ -0,0 +1,42 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+public class QtModelIndex
+{
+ public QtModelIndex() { }
+ public int column() { return (int)m_privateData[1]; }
+ public native Object data(int role);
+ public native long internalId();
+ public native boolean isValid();
+ public native QtModelIndex parent();
+ public int row() { return (int)m_privateData[0]; }
+
+ private long[] m_privateData = { -1 /*row*/, -1 /*column*/, 0 /*internalId*/,
+ 0 /*modelReference*/ };
+ private QtModelIndex m_parent = null;
+ private QtModelIndex(int row, int column, long internalId, long modelReference)
+ {
+ m_privateData[0] = row;
+ m_privateData[1] = column;
+ m_privateData[2] = internalId;
+ m_privateData[3] = modelReference;
+ m_parent = null;
+ }
+ private QtModelIndex(int row, int column, QtModelIndex parent, long modelReference)
+ {
+ m_privateData[0] = row;
+ m_privateData[1] = column;
+ m_privateData[2] = 0;
+ m_privateData[3] = modelReference;
+ m_parent = parent;
+ }
+ private void detachFromNative()
+ {
+ m_privateData[0] = -1;
+ m_privateData[1] = -1;
+ m_privateData[2] = 0;
+ m_privateData[3] = 0;
+ };
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQmlComponent.java b/src/quick/jar/org/qtproject/qt/android/QtQmlComponent.java
new file mode 100644
index 0000000000..fa52f8da6e
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtQmlComponent.java
@@ -0,0 +1,205 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.util.Log;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.HashSet;
+
+/**
+ * @Since 6.8
+ *
+ * The QtQmlComponent represents a QML component that can be loaded by a QtQuickView instance
+ * This abstract class should be extended to be used by a QtQuickView. It provides QtQuickView with
+ * essential information to load the QML component it represents.
+ * It also offers convenient methods for seamless interaction with the QtQuickView that loads it.
+ **/
+public abstract class QtQmlComponent
+{
+ private final static String TAG = "QtQmlComponent";
+
+ private WeakReference<QtQuickView> m_viewReference;
+ private QtQmlStatusChangeListener m_statusChangeListener = null;
+ private HashSet<Integer> m_signalListenerIds = new HashSet<>();
+
+ /**
+ * Implement this to return the library name that this component belongs to.
+ **/
+ protected abstract String getLibraryName();
+ /**
+ * Implement this to return the module name that this component belongs to.
+ **/
+ protected abstract String getModuleName();
+ /**
+ * Implement this to return the qrc (Qt Resource) path of this QML component.
+ **/
+ protected abstract String getFilePath();
+
+ /**
+ * Sets a StatusChangeListener to listen to status changes.
+ * <p>
+ * @param listener an instance of a StatusChangeListener interface
+ **/
+ public void setStatusChangeListener(QtQmlStatusChangeListener listener)
+ {
+ m_statusChangeListener = listener;
+ QtQuickView view = getQuickView();
+ if (view != null)
+ view.setStatusChangeListener(listener);
+ }
+
+ /**
+ * Gets the QtQuickView instance that has loaded this component.
+ * <p>
+ * @return Returns an instance of QtQuickView or null if this component is not loaded by any
+ * QtQuickView.
+ **/
+ protected QtQuickView getQuickView()
+ {
+ if (m_viewReference != null)
+ return m_viewReference.get();
+ return null;
+ }
+
+ /**
+ * Checks if this is currently attached to a QtQuickView instance
+ * <p>
+ * @return Returns true if this is attached to a QtQuickView instance, otherwise, returns false.
+ **/
+ protected boolean isViewAttached() { return getQuickView() != null; }
+
+ /**
+ * Attaches this to a QtQuickView instance.
+ **/
+ protected void attachView(QtQuickView view)
+ {
+ m_viewReference = new WeakReference<>(view);
+ if (view != null)
+ view.setStatusChangeListener(m_statusChangeListener);
+ }
+
+ /**
+ * Detaches this from the QtQuickView to which it has previously been attached. A call to this
+ * method will disconnect all signal listeners that have been connected before.
+ **/
+ protected void detachView()
+ {
+ QtQuickView view = getQuickView();
+ if (view != null) {
+ for (int signalListenerId : m_signalListenerIds)
+ view.disconnectSignalListener(signalListenerId);
+
+ view.setStatusChangeListener(null);
+ m_viewReference.clear();
+ if (m_statusChangeListener != null)
+ m_statusChangeListener.onStatusChanged(QtQmlStatus.NULL);
+ }
+ }
+
+ /**
+ * Implement this to return more information about the QML Component.
+ * Default implementation returns an empty HashMap.
+ **/
+ protected HashMap<String, Object> attributes() { return new HashMap<>(); }
+
+ /**
+ * Sets the value of an existing property on the QML component if it has already been attached
+ * and loaded by a QtQuickView instance. The supported types are
+ * {@link java.lang.Integer}, {@link java.lang.Double}, {@link java.lang.Float},
+ * {@link java.lang.Boolean} and {@link java.lang.String}. These types get converted to their
+ * corresponding QML types int, double/float, bool, and string. This function does not add
+ * properties to the QML root object if they do not exist but prints a warning.
+ * <p>
+ * @param propertyName the name of the existing QML property to set the value of
+ * @param value the value to set the property to
+ * @see <a href="https://doc.qt.io/qt-6/qml-int.html">QML int</a>,
+ * @see <a href="https://doc.qt.io/qt-6/qml-double.html">QML double/float</a>,
+ * @see <a href="https://doc.qt.io/qt-6/qml-bool.html">QML bool</a>,
+ * @see <a href="https://doc.qt.io/qt-6/qml-string.html">QML string</a>.
+ **/
+ protected void setProperty(String propertyName, Object value)
+ {
+ QtQuickView view = getQuickView();
+ if (view == null) {
+ Log.w(TAG, "Cannot set property as the QQmlComponent is not loaded in a QtQuickView.");
+ return;
+ }
+ view.setProperty(propertyName, value);
+ }
+
+ /**
+ * Gets the value of an existing property of the QML component if it has already been attached
+ * and loaded by a QtQuickView instance. The supported types are
+ * {@link java.lang.Integer}, {@link java.lang.Double}, {@link java.lang.Float},
+ * {@link java.lang.Boolean} and {@link java.lang.String}. These types get converted to their
+ * corresponding QML types int, double/float, bool and string. If the property does not
+ * exist or the status of the QML component is anything other than
+ * {@link QtQuickView#STATUS_READY STATUS_READY}, this function will return null.
+ * <p>
+ * @param propertyName the name of the existing root object property
+ * @throws ClassCastException if the returned type cannot be cast to the requested type.
+ * @see <a href="https://doc.qt.io/qt-6/qml-int.html">QML int</a>,
+ * @see <a href="https://doc.qt.io/qt-6/qml-double.html">QML double/float</a>,
+ * @see <a href="https://doc.qt.io/qt-6/qml-bool.html">QML bool</a>,
+ * @see <a href="https://doc.qt.io/qt-6/qml-string.html">QML string</a>.
+ **/
+ protected <T> T getProperty(String propertyName)
+ {
+ QtQuickView view = getQuickView();
+ if (view == null) {
+ Log.w(TAG, "Cannot get property as the QQmlComponent is not loaded in a QtQuickView.");
+ return null;
+ }
+ return view.<T>getProperty(propertyName);
+ }
+
+ /**
+ * Connects a SignalListener to a signal of the QML component if it has already been attached
+ * and loaded by a QtQuickView instance.
+ * <p>
+ * @param signalName the name of the root object signal
+ * @param argType the Class type of the signal argument
+ * @param listener an instance of the QtSignalListener interface
+ * @return a connection ID between signal and listener or the existing connection ID if there is
+ * an existing connection between the same signal and listener. Return a negative value
+ * if the signal does not exist on the QML root object.
+ **/
+ protected <T> int connectSignalListener(String signalName, Class<T> argType,
+ QtSignalListener<T> listener)
+ {
+ QtQuickView view = getQuickView();
+ if (view == null) {
+ Log.w(TAG,
+ "Cannot connect signal listener as the QQmlComponent is not loaded in a "
+ + "QtQuickView.");
+ return -1;
+ }
+ int signalListenerId = view.connectSignalListener(signalName, argType, listener);
+ m_signalListenerIds.add(signalListenerId);
+ return signalListenerId;
+ }
+
+ /**
+ * Disconnects a SignalListener with a given id obtained from
+ * {@link QtQuickView#connectSignalListener() connectSignalListener} call, from listening to
+ * a signal.
+ * <p>
+ * @param signalListenerId the connection id
+ * @return Returns true if the connection id is valid and has been successfully removed,
+ * otherwise returns false.
+ **/
+ public boolean disconnectSignalListener(int signalListenerId)
+ {
+ QtQuickView view = getQuickView();
+ if (view == null) {
+ Log.w(TAG,
+ "Cannot disconnect signal listener as the QQmlComponent is not loaded in a "
+ + "QtQuickView.");
+ return false;
+ }
+ m_signalListenerIds.remove(signalListenerId);
+ return view.disconnectSignalListener(signalListenerId);
+ }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQmlStatus.java b/src/quick/jar/org/qtproject/qt/android/QtQmlStatus.java
new file mode 100644
index 0000000000..02bea77d43
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtQmlStatus.java
@@ -0,0 +1,49 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import java.lang.IllegalArgumentException;
+
+/**
+ * QtQmlStatus represents the QML component loading status.
+ */
+public enum QtQmlStatus {
+ /**
+ * Not loaded.
+ **/
+ NULL(0),
+
+ /**
+ * Loaded and ready.
+ * Invoking methods that operate on a QML component would succeed <b>only<b> if
+ * the current status is ready.
+ **/
+ READY(1),
+
+ /**
+ *The QML component is getting loaded from network.
+ **/
+ LOADING(2),
+
+ /**
+ * One or more errors has occurred during loading the QML component.
+ **/
+ ERROR(3);
+
+ private final int m_value;
+
+ QtQmlStatus(int value) { this.m_value = value; }
+
+ QtQmlStatus() { this.m_value = ordinal(); }
+
+ static QtQmlStatus fromInt(int value) throws IllegalArgumentException
+ {
+ for (QtQmlStatus enumValue : QtQmlStatus.values()) {
+ if (enumValue.m_value == value) {
+ return enumValue;
+ }
+ }
+ throw new IllegalArgumentException("No QtQmlStatus enum with value " + value);
+ }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQmlStatusChangeListener.java b/src/quick/jar/org/qtproject/qt/android/QtQmlStatusChangeListener.java
new file mode 100644
index 0000000000..f1190ed8b1
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtQmlStatusChangeListener.java
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+/**
+ * A callback that notifies clients about the status of QML component loading.
+ **/
+public interface QtQmlStatusChangeListener
+{
+ /**
+ * Called on the Android UI thread when the QML component status has changed.
+ * @param status The current status. The status can be QtQmlStatus.NULL,
+ * QtQmlStatus.READY, QtQmlStatus.LOADING, or QtQmlStatus.ERROR.
+ **/
+ void onStatusChanged(QtQmlStatus status);
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQuickView.java b/src/quick/jar/org/qtproject/qt/android/QtQuickView.java
index 0f8e999d96..710756adee 100644
--- a/src/quick/jar/org/qtproject/qt/android/QtQuickView.java
+++ b/src/quick/jar/org/qtproject/qt/android/QtQuickView.java
@@ -8,6 +8,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.util.Log;
+import java.lang.IllegalArgumentException;
+import java.lang.ref.WeakReference;
import java.security.InvalidParameterException;
/**
@@ -32,62 +34,15 @@ import java.security.InvalidParameterException;
public class QtQuickView extends QtView {
private final static String TAG = "QtQuickView";
- /**
- * A callback that notifies clients when a signal is emitted from the QML root object.
- **/
- @FunctionalInterface
- public interface SignalListener<T>
- {
- /**
- * Called on the Android UI thread when the signal has been emitted.
- * @param signalName literal signal name
- * @param value the value delivered by the signal or null if the signal is parameterless
- **/
- void onSignalEmitted(String signalName, T value);
- }
-
- /**
- * A callback that notifies clients about the status of QML loading.
- **/
- public interface StatusChangeListener
- {
- /**
- * Called on the Android UI thread when the QML component status has changed.
- * @param status The current status. The status can be STATUS_NULL, STATUS_READY,
- * STATUS_LOADING or STATUS_ERROR.
- **/
- void onStatusChanged(int status);
- }
-
- /**
- * QML loading status: No source is set or the root object has not been created yet.
- **/
- public static final int STATUS_NULL = 0;
- /**
- * QML loading status: The QML view is loaded and the root object is available.
- * Invoking methods that operate on the QML root object, i.e.
- * {@link QtQuickView#setProperty() setProperty}, {@link QtQuickView#getProperty() getProperty},
- * and {@link QtQuickView#addSignalListener() addSignalListener} would succeed <b>only<b> if
- * the current status is ready.
- **/
- public static final int STATUS_READY = 1;
- /**
- * QML loading status: The QML view is loading the root object from network.
- **/
- public static final int STATUS_LOADING = 2;
- /**
- * QML loading status: One or more errors has occurred.
- **/
- public static final int STATUS_ERROR = 3;
-
private String m_qmlUri;
private String[] m_qmlImportPaths = null;
- private StatusChangeListener m_statusChangeListener = null;
- private int m_lastStatus = STATUS_NULL;
+ private QtQmlStatusChangeListener m_statusChangeListener = null;
+ private QtQmlStatus m_lastStatus = QtQmlStatus.NULL;
private boolean m_hasQueuedStatus = false;
+ private WeakReference<QtQmlComponent> m_loadedComponent;
native void createQuickView(String qmlUri, int width, int height, long parentWindowReference,
- String[] qmlImportPaths);
+ long viewReference, String[] qmlImportPaths);
native void setRootObjectProperty(long windowReference, String propertyName, Object value);
native Object getRootObjectProperty(long windowReference, String propertyName);
native int addRootObjectSignalListener(long windowReference, String signalName, Class argType,
@@ -138,9 +93,85 @@ public class QtQuickView extends QtView {
m_qmlImportPaths = qmlImportPaths;
}
+ /**
+ * Creates a QtQuickView that can later load and view a QML component by calling
+ * {@link QtQuickView#loadComponent() loadComponent}
+ * <p>
+ * @param context the parent Context
+ **/
+ public QtQuickView(Context context)
+ {
+ super(context);
+ }
+
+ /**
+ * Loads a QML component represented by a QtQmlComponent. The library name and the qrc path of
+ * the QML component will be extracted from the QtQmlComponent to load the QML component.
+ * This overload accepts an array of strings in the case where the QML component should load
+ * QML modules from custom paths.
+ * <p>
+ * @param qmlComponent an instance of an object that extends QtQmlComponent
+ * @param qmlImportPaths an array of strings for additional import paths to be passed to
+ * QQmlEngine, or null if additional import paths are not required
+ * @throws InvalidParameterException if QtQmlComponent does not contain valid information
+ * about the module name, and the qrc path.
+ */
+ // TODO: QTBUG-125620 -- Refresh/reset import paths when loading a new component
+ public <T extends QtQmlComponent> void loadComponent(T qmlComponent, String[] qmlImportPaths)
+ throws InvalidParameterException
+ {
+ String libName = qmlComponent.getLibraryName();
+ String qmlUri = qmlComponent.getFilePath();
+
+ if (libName == null || libName.isEmpty()) {
+ throw new InvalidParameterException(
+ "QtQmlComponent: return value of getLibraryName() may not be empty or null");
+ }
+
+ if (qmlUri == null || qmlUri.isEmpty()) {
+ throw new InvalidParameterException(
+ "QtQmlComponent: return value of getFilePath() may not be empty or null");
+ }
+
+ m_qmlUri = qmlUri;
+ m_qmlImportPaths = qmlImportPaths;
+
+ if (m_loadedComponent != null)
+ m_loadedComponent.clear();
+
+ m_loadedComponent = new WeakReference<>(qmlComponent);
+ qmlComponent.detachView();
+ qmlComponent.attachView(this);
+ // The first QQuickView creation happen after first libs loading
+ // and windowReference() returns a reference to native QQuickView
+ // instance, after that. We don't load library again if the view
+ // exists.
+ if (windowReference() == 0) {
+ loadQtLibraries(libName);
+ } else {
+ createQuickView(m_qmlUri, getWidth(), getHeight(), 0, windowReference(),
+ m_qmlImportPaths);
+ }
+ }
+
+ /**
+ * Loads a QML component represented by a QtQmlComponent. The library name and the qrc path of
+ * the QML component will be extracted from the QtQmlComponent to load the QML component.
+ * <p>
+ * @param qmlComponent an instance of a class that extends QtQmlComponent
+ * @throws InvalidParameterException if QtQmlComponent does not contain valid information
+ * about the module name, and the qrc path.
+ */
+ public <T extends QtQmlComponent> void loadComponent(T qmlComponent)
+ throws InvalidParameterException
+ {
+ loadComponent(qmlComponent, null);
+ }
+
@Override
protected void createWindow(long parentWindowReference) {
- createQuickView(m_qmlUri, getWidth(), getHeight(), parentWindowReference, m_qmlImportPaths);
+ createQuickView(m_qmlUri, getWidth(), getHeight(), parentWindowReference, windowReference(),
+ m_qmlImportPaths);
}
/**
@@ -190,13 +221,13 @@ public class QtQuickView extends QtView {
* <p>
* @param signalName the name of the root object signal
* @param argType the Class type of the signal argument
- * @param listener an instance of the SignalListener interface
+ * @param listener an instance of the QtSignalListener interface
* @return a connection id between signal and listener or the existing connection id if there is
* an existing connection between the same signal and listener. Return a negative value
* if the signal does not exists on the QML root object.
**/
public <T> int connectSignalListener(String signalName, Class<T> argType,
- SignalListener<T> listener)
+ QtSignalListener<T> listener)
{
int signalListenerId =
addRootObjectSignalListener(windowReference(), signalName, argType, listener);
@@ -224,25 +255,25 @@ public class QtQuickView extends QtView {
/**
* Gets the status of the QML component.
* <p>
- * @return Returns STATUS_READY when the QML component is ready. Invoking methods that operate
- * on the QML root object ({@link QtQuickView#setProperty() setProperty},
+ * @return Returns QtQmlStatus.READY when the QML component is ready. Invoking methods that
+ * operate on the QML root object ({@link QtQuickView#setProperty() setProperty},
* {@link QtQuickView#getProperty() getProperty}, and
* {@link QtQuickView#addSignalListener() addSignalListener}) would succeed <b>only</b>
- * if the current STATUS_READY. It can also return STATUS_NULL, STATUS_LOADING, or
- * STATUS_ERROR based on the status of see underlaying
+ * if the current status is QtQmlStatus.READY. It can also return QtQmlStatus.NULL,
+ * QtQmlStatus.LOADING, or QtQmlStatus.ERROR based on the status of the underlaying
* @see <a href="https://doc.qt.io/qt-6/qquickview.html">QQuickView</a> instance.
**/
- public int getStatus()
+ public QtQmlStatus getStatus()
{
return m_lastStatus;
}
/**
- * Sets a StatusChangeListener to listen to status changes.
+ * Sets a QtQmlStatusChangeListener to listen to status changes.
* <p>
- * @param listener an instance of a StatusChangeListener interface
+ * @param listener an instance of a QtQmlStatusChangeListener interface
**/
- public void setStatusChangeListener(StatusChangeListener listener)
+ public void setStatusChangeListener(QtQmlStatusChangeListener listener)
{
m_statusChangeListener = listener;
@@ -254,10 +285,17 @@ public class QtQuickView extends QtView {
private void handleStatusChange(int status)
{
- m_lastStatus = status;
+ try {
+ m_lastStatus = QtQmlStatus.fromInt(status);
+ } catch (IllegalArgumentException e) {
+ m_lastStatus = QtQmlStatus.NULL;
+ e.printStackTrace();
+ }
if (m_statusChangeListener != null)
- QtNative.runAction(() -> { m_statusChangeListener.onStatusChanged(status); });
+ QtNative.runAction(() -> {
+ m_statusChangeListener.onStatusChanged(QtQmlStatus.fromInt(status));
+ });
else
m_hasQueuedStatus = true;
}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc b/src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc
index 11c94fe8d6..d603ac4144 100644
--- a/src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc
+++ b/src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc
@@ -60,7 +60,45 @@
}
\endcode
- For a more detailed example, see \l {QML in Java-Based Android Projects}.
+ For a more detailed example, see \l {QML in Android Studio Projects}.
+
+ \section1 QtQuickView in an Android Service
+
+ It is also possible to add a QtQuickView from a Service context by using
+ the Android WindowManager interface:
+
+ \code
+ @Override
+ public void onCreate() {
+ m_windowManager = getSystemService(WindowManager.class);
+ m_qtView = new QtQuickView(this, "qrc:/qt/qml/target/main.qml", "target");
+ WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
+ 640, 320,
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
+ PixelFormat.TRANSLUCENT);
+ m_windowManager.addView(m_qtView, layoutParams);
+ }
+ \endcode
+
+ To clean up the QtQuickView and Qt libraries, the onDestroy() lifecycle
+ function can be used:
+
+ \code
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ m_windowManager.removeView(m_qtView);
+ m_qtView = null;
+ }
+ \endcode
+
+ \note Adding a QtQuickView from a Service context requires your application
+ to have the \l {Android: SYSTEM_ALERT_WINDOW}{SYSTEM_ALERT_WINDOW}
+ permission, and to be signed with the platform key.
+
+ \note QML views embedded within a Service context do not
+ support keyboard input or accessibility features.
\section1 Constructors
diff --git a/src/quick/jar/org/qtproject/qt/android/QtSignalListener.java b/src/quick/jar/org/qtproject/qt/android/QtSignalListener.java
new file mode 100644
index 0000000000..195f983be4
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtSignalListener.java
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+/**
+ * A callback that notifies clients when a signal is emitted from the QML component.
+ **/
+@FunctionalInterface
+public interface QtSignalListener<T> {
+ /**
+ * Called on the Android UI thread when the signal has been emitted.
+ * @param signalName literal signal name
+ * @param value the value delivered by the signal or null if the signal is parameterless
+ **/
+ void onSignalEmitted(String signalName, T value);
+}
diff --git a/src/quick/platform/android/qandroiditemmodelproxy.cpp b/src/quick/platform/android/qandroiditemmodelproxy.cpp
new file mode 100644
index 0000000000..46b13f62c6
--- /dev/null
+++ b/src/quick/platform/android/qandroiditemmodelproxy.cpp
@@ -0,0 +1,379 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtQuick/private/qandroiditemmodelproxy_p.h>
+#include <QtQuick/private/qandroidmodelindexproxy_p.h>
+#include <QtQuick/private/qandroidtypeconverter_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtJniTypes;
+
+jint QAndroidItemModelProxy::columnCount(const QModelIndex &parent) const
+{
+ Q_ASSERT(jInstance.isValid());
+ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
+ return jInstance.callMethod<jint>("columnCount", parentIndex);
+}
+
+bool QAndroidItemModelProxy::canFetchMore(const QModelIndex &parent) const
+{
+ Q_ASSERT(jInstance.isValid());
+ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
+ return jInstance.callMethod<jboolean>("canFetchMore", parentIndex);
+}
+
+bool QAndroidItemModelProxy::canFetchMoreDefault(const QModelIndex &parent) const
+{
+ return QAbstractItemModel::canFetchMore(parent);
+}
+
+QVariant QAndroidItemModelProxy::data(const QModelIndex &index, int role) const
+{
+ Q_ASSERT(jInstance.isValid());
+ auto jIndex = QAndroidModelIndexProxy::jInstance(index);
+ QJniObject jData = jInstance.callMethod<jobject>("data", jIndex, role);
+ return QAndroidTypeConverter::toQVariant(jData);
+}
+
+QModelIndex QAndroidItemModelProxy::index(int row, int column, const QModelIndex &parent) const
+{
+ Q_ASSERT(jInstance.isValid());
+ JQtModelIndex jIndex = jInstance.callMethod<JQtModelIndex>(
+ "index", row, column, QAndroidModelIndexProxy::jInstance(parent));
+ return QAndroidModelIndexProxy::qInstance(jIndex);
+}
+
+QModelIndex QAndroidItemModelProxy::parent(const QModelIndex &index) const
+{
+ Q_ASSERT(jInstance.isValid());
+
+ auto jIndex = QAndroidModelIndexProxy::jInstance(index);
+ return QAndroidModelIndexProxy::qInstance(
+ jInstance.callMethod<JQtModelIndex>("parent", jIndex));
+}
+int QAndroidItemModelProxy::rowCount(const QModelIndex &parent) const
+{
+ Q_ASSERT(jInstance.isValid());
+
+ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
+ return jInstance.callMethod<int>("rowCount", parentIndex);
+}
+
+QHash<int, QByteArray> QAndroidItemModelProxy::roleNames() const
+{
+ Q_ASSERT(jInstance.isValid());
+
+ QHash<int, QByteArray> roleNames;
+ JHashMap hashMap = jInstance.callMethod<JHashMap>("roleNames");
+ JSet set = hashMap.callMethod<JSet>("keySet");
+ QJniArray<jobject> keyArray = set.callMethod<QJniArray<jobject>>("toArray");
+
+ for (auto key : keyArray) {
+ const QJniObject roleName = hashMap.callMethod<jobject>("get", key);
+ const int intKey = QJniObject(key).callMethod<jint>("intValue");
+ const QByteArray roleByteArray = String(roleName).toString().toLatin1();
+ roleNames.insert(intKey, roleByteArray);
+ }
+ return roleNames;
+}
+
+QHash<int, QByteArray> QAndroidItemModelProxy::defaultRoleNames() const
+{
+ return QAbstractItemModel::roleNames();
+}
+
+void QAndroidItemModelProxy::fetchMore(const QModelIndex &parent)
+{
+ Q_ASSERT(jInstance.isValid());
+ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
+ jInstance.callMethod<void>("fetchMore", parentIndex);
+}
+
+void QAndroidItemModelProxy::fetchMoreDefault(const QModelIndex &parent)
+{
+ QAbstractItemModel::fetchMore(parent);
+}
+
+bool QAndroidItemModelProxy::hasChildren(const QModelIndex &parent) const
+{
+ Q_ASSERT(jInstance.isValid());
+ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
+ return jInstance.callMethod<jboolean>("hasChildren", parentIndex);
+}
+
+bool QAndroidItemModelProxy::hasChildrenDefault(const QModelIndex &parent) const
+{
+ return QAbstractItemModel::hasChildren(parent);
+}
+
+QModelIndex QAndroidItemModelProxy::sibling(int row, int column, const QModelIndex &parent) const
+{
+ Q_ASSERT(jInstance.isValid());
+ return QAndroidModelIndexProxy::qInstance(jInstance.callMethod<jobject>(
+ "sibling", row, column, QAndroidModelIndexProxy::jInstance(parent)));
+}
+
+QModelIndex QAndroidItemModelProxy::siblingDefault(int row, int column, const QModelIndex &parent)
+{
+ return QAbstractItemModel::sibling(row, column, parent);
+}
+
+Q_REQUIRED_RESULT QAbstractItemModel *
+QAndroidItemModelProxy::nativeInstance(JQtAbstractItemModel itemModel)
+{
+ jlong nativeReference = itemModel.callMethod<jlong>("nativeReference");
+ return reinterpret_cast<QAbstractItemModel *>(nativeReference);
+}
+
+Q_REQUIRED_RESULT QAbstractItemModel *
+QAndroidItemModelProxy::createNativeProxy(QJniObject itemModel)
+{
+ QAbstractItemModel *nativeProxy = nativeInstance(itemModel);
+ if (!nativeProxy) {
+ nativeProxy = new QAndroidItemModelProxy(itemModel);
+
+ itemModel.callMethod<void>("setNativeReference", reinterpret_cast<jlong>(nativeProxy));
+ connect(nativeProxy, &QAndroidItemModelProxy::destroyed, nativeProxy, [](QObject *obj) {
+ auto proxy = qobject_cast<QAndroidItemModelProxy *>(obj);
+ if (proxy)
+ proxy->jInstance.callMethod<void>("detachFromNative");
+ });
+ }
+ return nativeProxy;
+}
+
+QJniObject QAndroidItemModelProxy::createProxy(QAbstractItemModel *itemModel)
+{
+ return JQtAndroidItemModelProxy(reinterpret_cast<jlong>(itemModel));
+}
+
+int QAndroidItemModelProxy::jni_columnCount(JNIEnv *env, jobject object, JQtModelIndex parent)
+{
+ const QModelIndex nativeParent = QAndroidModelIndexProxy::qInstance(parent);
+ return invokeNativeMethod(env, object, &QAbstractItemModel::columnCount, nativeParent);
+}
+
+jobject QAndroidItemModelProxy::jni_data(JNIEnv *env, jobject object, JQtModelIndex index,
+ jint role)
+{
+ const QModelIndex nativeIndex = QAndroidModelIndexProxy::qInstance(index);
+ const QVariant data =
+ invokeNativeMethod(env, object, &QAbstractItemModel::data, nativeIndex, role);
+ return QAndroidTypeConverter::toJavaObject(data, env);
+}
+
+jobject QAndroidItemModelProxy::jni_index(JNIEnv *env, jobject object, jint row, jint column,
+ JQtModelIndex parent)
+{
+ auto nativeParent = QAndroidModelIndexProxy::qInstance(parent);
+ const QModelIndex modelIndex =
+ invokeNativeMethod(env, object, &QAbstractItemModel::index, row, column, nativeParent);
+ return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(modelIndex).object());
+}
+
+jobject QAndroidItemModelProxy::jni_parent(JNIEnv *env, jobject object, JQtModelIndex index)
+{
+ const QModelIndex nativeIndex = QAndroidModelIndexProxy::qInstance(index);
+ QModelIndex (QAbstractItemModel::*parentOverloadPtr)(const QModelIndex &) const =
+ &QAbstractItemModel::parent;
+ const QModelIndex parent = invokeNativeMethod(env, object, parentOverloadPtr, nativeIndex);
+ return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(parent).object());
+}
+
+jint QAndroidItemModelProxy::jni_rowCount(JNIEnv *env, jobject object, JQtModelIndex parent)
+{
+ return invokeNativeMethod(env, object, &QAbstractItemModel::rowCount,
+ QAndroidModelIndexProxy::qInstance(parent));
+}
+
+jobject QAndroidItemModelProxy::jni_roleNames(JNIEnv *env, jobject object)
+{
+ auto roleNames = invokeNativeImpl(env, object, &QAndroidItemModelProxy::defaultRoleNames,
+ &QAbstractItemModel::roleNames);
+ JHashMap jRoleNames{};
+ for (auto [role, roleName] : roleNames.asKeyValueRange()) {
+ const Integer jRole(role);
+ const QJniObject jRoleName = QJniObject::fromString(roleName);
+ jRoleNames.callMethod<jobject>("put", jRole.object(), jRoleName.object());
+ }
+ return env->NewLocalRef(jRoleNames.object());
+}
+
+jobject QAndroidItemModelProxy::jni_createIndex(JNIEnv *env, jobject object, jint row, jint column,
+ jlong id)
+{
+ QModelIndex (QAndroidItemModelProxy::*createIndexPtr)(int, int, quintptr) const =
+ &QAndroidItemModelProxy::createIndex;
+ const QModelIndex index = invokeNativeProxyMethod(env, object, createIndexPtr, row, column, id);
+ return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(index).object());
+}
+
+jboolean QAndroidItemModelProxy::jni_canFetchMore(JNIEnv *env, jobject object, JQtModelIndex parent)
+{
+ return invokeNativeImpl(env, object, &QAndroidItemModelProxy::canFetchMoreDefault,
+ &QAbstractItemModel::canFetchMore,
+ QAndroidModelIndexProxy::qInstance(parent));
+}
+
+void QAndroidItemModelProxy::jni_fetchMore(JNIEnv *env, jobject object, JQtModelIndex parent)
+{
+ return invokeNativeImpl(env, object, &QAndroidItemModelProxy::fetchMoreDefault,
+ &QAbstractItemModel::fetchMore,
+ QAndroidModelIndexProxy::qInstance(parent));
+}
+
+jboolean QAndroidItemModelProxy::jni_hasChildren(JNIEnv *env, jobject object, JQtModelIndex parent)
+{
+ return invokeNativeImpl(env, object, &QAndroidItemModelProxy::hasChildrenDefault,
+ &QAbstractItemModel::hasChildren,
+ QAndroidModelIndexProxy::qInstance(parent));
+}
+
+jboolean QAndroidItemModelProxy::jni_hasIndex(JNIEnv *env, jobject object, jint row, jint column,
+ JQtModelIndex parent)
+{
+ return invokeNativeMethod(env, object, &QAbstractItemModel::hasIndex, row, column,
+ QAndroidModelIndexProxy::qInstance(parent));
+}
+
+void QAndroidItemModelProxy::jni_beginInsertColumns(JNIEnv *env, jobject object,
+ JQtModelIndex parent, jint first, jint last)
+{
+
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginInsertColumns,
+ QAndroidModelIndexProxy::qInstance(parent), first, last);
+}
+
+void QAndroidItemModelProxy::jni_beginInsertRows(JNIEnv *env, jobject object, JQtModelIndex parent,
+ jint first, jint last)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginInsertRows,
+ QAndroidModelIndexProxy::qInstance(parent), first, last);
+}
+
+jboolean QAndroidItemModelProxy::jni_beginMoveColumns(JNIEnv *env, jobject object,
+ JQtModelIndex sourceParent, jint sourceFirst,
+ jint sourceLast,
+ JQtModelIndex destinationParent,
+ jint destinationChild)
+{
+ return invokeNativeProxyMethod(
+ env, object, &QAndroidItemModelProxy::beginMoveColumns,
+ QAndroidModelIndexProxy::qInstance(sourceParent), sourceFirst, sourceLast,
+ QAndroidModelIndexProxy::qInstance(destinationParent), destinationChild);
+}
+
+jboolean QAndroidItemModelProxy::jni_beginMoveRows(JNIEnv *env, jobject object,
+ JQtModelIndex sourceParent, jint sourceFirst,
+ jint sourceLast, JQtModelIndex destinationParent,
+ jint destinationChild)
+{
+ return invokeNativeProxyMethod(
+ env, object, &QAndroidItemModelProxy::beginMoveRows,
+ QAndroidModelIndexProxy::qInstance(sourceParent), sourceFirst, sourceLast,
+ QAndroidModelIndexProxy::qInstance(destinationParent), destinationChild);
+}
+
+void QAndroidItemModelProxy::jni_beginRemoveColumns(JNIEnv *env, jobject object,
+ JQtModelIndex parent, jint first, jint last)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginRemoveColumns,
+ QAndroidModelIndexProxy::qInstance(parent), first, last);
+}
+
+void QAndroidItemModelProxy::jni_beginRemoveRows(JNIEnv *env, jobject object, JQtModelIndex parent,
+ jint first, jint last)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginRemoveRows,
+ QAndroidModelIndexProxy::qInstance(parent), first, last);
+}
+
+void QAndroidItemModelProxy::jni_beginResetModel(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginResetModel);
+}
+
+void QAndroidItemModelProxy::jni_endInsertColumns(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endInsertColumns);
+}
+
+void QAndroidItemModelProxy::jni_endInsertRows(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endInsertRows);
+}
+
+void QAndroidItemModelProxy::jni_endMoveColumns(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endMoveColumns);
+}
+
+void QAndroidItemModelProxy::jni_endMoveRows(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endMoveRows);
+}
+
+void QAndroidItemModelProxy::jni_endRemoveColumns(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endRemoveColumns);
+}
+
+void QAndroidItemModelProxy::jni_endRemoveRows(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endRemoveRows);
+}
+
+void QAndroidItemModelProxy::jni_endResetModel(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endResetModel);
+}
+
+jobject QAndroidItemModelProxy::jni_sibling(JNIEnv *env, jobject object, jint row, jint column,
+ JQtModelIndex parent)
+{
+ const QModelIndex index = invokeNativeImpl(env, object, &QAndroidItemModelProxy::siblingDefault,
+ &QAbstractItemModel::sibling, row, column,
+ QAndroidModelIndexProxy::qInstance(parent));
+ return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(index).object());
+}
+
+bool QAndroidItemModelProxy::registerAbstractNatives(QJniEnvironment &env)
+{
+ return env.registerNativeMethods(
+ Traits<JQtAbstractItemModel>::className(),
+ { Q_JNI_NATIVE_SCOPED_METHOD(jni_roleNames, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_canFetchMore, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_createIndex, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_fetchMore, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_hasChildren, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_hasIndex, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginInsertColumns, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginInsertRows, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginMoveColumns, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginMoveRows, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginRemoveColumns, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginRemoveRows, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginResetModel, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endInsertColumns, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endInsertRows, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endMoveColumns, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endMoveRows, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endRemoveColumns, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endRemoveRows, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endResetModel, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_sibling, QAndroidItemModelProxy) });
+}
+
+bool QAndroidItemModelProxy::registerProxyNatives(QJniEnvironment &env)
+{
+ return env.registerNativeMethods(
+ Traits<JQtAndroidItemModelProxy>::className(),
+ { Q_JNI_NATIVE_SCOPED_METHOD(jni_columnCount, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_data, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_index, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_parent, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_rowCount, QAndroidItemModelProxy) });
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/platform/android/qandroiditemmodelproxy_p.h b/src/quick/platform/android/qandroiditemmodelproxy_p.h
new file mode 100644
index 0000000000..6670395596
--- /dev/null
+++ b/src/quick/platform/android/qandroiditemmodelproxy_p.h
@@ -0,0 +1,191 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QANDROIDITEMMODELPROXY_P_H
+#define QANDROIDITEMMODELPROXY_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#include <QtQuick/private/qandroidmodelindexproxy_p.h>
+#include <QtQuick/private/qandroidtypes_p.h>
+#include <QtQuick/private/qtquickglobal_p.h>
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjnitypes.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_EXPORT QAndroidItemModelProxy : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ explicit QAndroidItemModelProxy(QtJniTypes::JQtAbstractItemModel jInstance)
+ : jInstance(jInstance)
+ {
+ }
+
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ QModelIndex index(int row, int column,
+ const QModelIndex &parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex &index) const override;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ bool canFetchMore(const QModelIndex &parent) const override;
+ bool canFetchMoreDefault(const QModelIndex &parent) const;
+ QHash<int, QByteArray> roleNames() const override;
+ QHash<int, QByteArray> defaultRoleNames() const;
+ void fetchMore(const QModelIndex &parent) override;
+ void fetchMoreDefault(const QModelIndex &parent);
+ bool hasChildren(const QModelIndex &parent) const override;
+ bool hasChildrenDefault(const QModelIndex &parent) const;
+ QModelIndex sibling(int row, int column, const QModelIndex &parent) const override;
+ QModelIndex siblingDefault(int row, int column, const QModelIndex &parent);
+
+ Q_REQUIRED_RESULT static QAbstractItemModel *
+ nativeInstance(QtJniTypes::JQtAbstractItemModel itemModel);
+ Q_REQUIRED_RESULT static QAbstractItemModel *createNativeProxy(QJniObject itemModel);
+ static QJniObject createProxy(QAbstractItemModel *abstractClass);
+
+ template <typename Func, typename... Args>
+ static auto invokeNativeProxyMethod(JNIEnv */*env*/, jobject jvmObject, Func func, Args &&...args)
+ {
+ Q_ASSERT(jvmObject);
+ auto model = qobject_cast<QAndroidItemModelProxy *>(nativeInstance(jvmObject));
+ Q_ASSERT(model);
+ return std::invoke(func, model, std::forward<Args>(args)...);
+ }
+
+ template <typename Func, typename... Args>
+ static auto invokeNativeMethod(JNIEnv */*env*/, jobject jvmObject, Func func, Args &&...args)
+ {
+ Q_ASSERT(jvmObject);
+ auto model = nativeInstance(jvmObject);
+ Q_ASSERT(model);
+ return std::invoke(func, model, std::forward<Args>(args)...);
+ }
+
+ template <typename Func1, typename Func2, typename... Args>
+ static auto invokeNativeImpl(JNIEnv */*env*/, jobject jvmObject, Func1 defaultFunc, Func2 func,
+ Args &&...args)
+ {
+ Q_ASSERT(jvmObject);
+ auto nativeModel = nativeInstance(jvmObject);
+ auto nativeProxyModel = qobject_cast<QAndroidItemModelProxy *>(nativeModel);
+ if (nativeProxyModel)
+ return std::invoke(defaultFunc, nativeProxyModel, std::forward<Args>(args)...);
+ else
+ return std::invoke(func, nativeModel, std::forward<Args>(args)...);
+ }
+
+ static jint jni_columnCount(JNIEnv *env, jobject object, JQtModelIndex parent);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_columnCount)
+
+ static jobject jni_data(JNIEnv *env, jobject object, JQtModelIndex index, jint role);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_data)
+
+ static jobject jni_index(JNIEnv *env, jobject object, jint row, jint column,
+ JQtModelIndex parent);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_index)
+
+ static jobject jni_parent(JNIEnv *env, jobject object, JQtModelIndex index);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_parent)
+
+ static jint jni_rowCount(JNIEnv *env, jobject object, JQtModelIndex parent);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_rowCount)
+
+ static jboolean jni_canFetchMore(JNIEnv *env, jobject object, JQtModelIndex parent);
+ QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(jni_canFetchMore, canFetchMore)
+
+ static void jni_fetchMore(JNIEnv *env, jobject object, JQtModelIndex parent);
+ QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(jni_fetchMore, fetchMore)
+
+ static jboolean jni_hasChildren(JNIEnv *env, jobject object, JQtModelIndex parent);
+ QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(jni_hasChildren, hasChildren)
+
+ static jboolean jni_hasIndex(JNIEnv *env, jobject object, jint row, jint column,
+ JQtModelIndex parent);
+ QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(jni_hasIndex, hasIndex)
+
+ static jobject jni_roleNames(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_roleNames)
+
+ static void jni_beginInsertColumns(JNIEnv *env, jobject object, JQtModelIndex parent,
+ jint first, jint last);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginInsertColumns)
+
+ static void jni_beginInsertRows(JNIEnv *env, jobject object, JQtModelIndex parent, jint first,
+ jint last);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginInsertRows)
+
+ static jboolean jni_beginMoveColumns(JNIEnv *env, jobject object, JQtModelIndex sourceParent,
+ jint sourceFirst, jint sourceLast,
+ JQtModelIndex destinationParent, jint destinationChild);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginMoveColumns)
+
+ static jboolean jni_beginMoveRows(JNIEnv *env, jobject object, JQtModelIndex sourceParent,
+ jint sourceFirst, jint sourceLast,
+ JQtModelIndex destinationParent, jint destinationChild);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginMoveRows)
+
+ static void jni_beginRemoveColumns(JNIEnv *env, jobject object, JQtModelIndex parent,
+ jint first, jint last);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginRemoveColumns)
+
+ static void jni_beginRemoveRows(JNIEnv *env, jobject object, JQtModelIndex parent, jint first,
+ jint last);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginRemoveRows)
+
+ static void jni_beginResetModel(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginResetModel)
+
+ static jobject jni_createIndex(JNIEnv *env, jobject object, jint row, jint column, jlong id);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_createIndex)
+
+ static void jni_endInsertColumns(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endInsertColumns)
+
+ static void jni_endInsertRows(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endInsertRows)
+
+ static void jni_endMoveColumns(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endMoveColumns)
+
+ static void jni_endMoveRows(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endMoveRows)
+
+ static void jni_endRemoveColumns(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endRemoveColumns)
+
+ static void jni_endRemoveRows(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endRemoveRows)
+
+ static void jni_endResetModel(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endResetModel)
+
+ static jobject jni_sibling(JNIEnv *env, jobject object, jint row, jint column,
+ JQtModelIndex parent);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_sibling)
+
+ static bool registerAbstractNatives(QJniEnvironment &env);
+ static bool registerProxyNatives(QJniEnvironment &env);
+
+private:
+ QJniObject jInstance;
+ friend class QAndroidModelIndexProxy;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDITEMMODELPROXY_P_H
diff --git a/src/quick/platform/android/qandroidmodelindexproxy.cpp b/src/quick/platform/android/qandroidmodelindexproxy.cpp
new file mode 100644
index 0000000000..b749d9f344
--- /dev/null
+++ b/src/quick/platform/android/qandroidmodelindexproxy.cpp
@@ -0,0 +1,103 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtQuick/private/qandroiditemmodelproxy_p.h>
+#include <QtQuick/private/qandroidmodelindexproxy_p.h>
+#include <QtQuick/private/qandroidtypeconverter_p.h>
+
+#include <QtCore/qjniarray.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtJniTypes;
+
+QModelIndex QAndroidModelIndexProxy::qInstance(JQtModelIndex jModelIndex)
+{
+ if (!jModelIndex.isValid())
+ return QModelIndex();
+
+ const QJniArray<jlong> jPrivateArray = jModelIndex.getField<jlong[]>("m_privateData");
+ const auto privateData = jPrivateArray.toContainer();
+ Q_ASSERT(privateData.size() == 4);
+
+ const jlong modelReference = privateData[3];
+ if (!modelReference)
+ return QModelIndex();
+
+ const jint row = privateData[0];
+ const jint column = privateData[1];
+ QAbstractItemModel *model = reinterpret_cast<QAbstractItemModel *>(modelReference);
+ QAndroidItemModelProxy *proxyModel = qobject_cast<QAndroidItemModelProxy *>(model);
+
+ // If the native model instance is a proxy we have access to the protected function
+ // createIndex(). Else, if the native instance is not a results Java->Qt proxy, we
+ // use index() to get the QModelIndex.
+ if (proxyModel) {
+ const jint internalId = privateData[2];
+ return proxyModel->createIndex(row, column, internalId);
+ } else {
+ const JQtModelIndex parent = jModelIndex.getField<JQtModelIndex>("m_parent");
+ if (parent.isValid())
+ return model->index(row, column, QAndroidModelIndexProxy::qInstance(parent));
+ }
+ return QModelIndex();
+}
+
+JQtModelIndex QAndroidModelIndexProxy::jInstance(QModelIndex modelIndex)
+{
+ if (!modelIndex.isValid())
+ return JQtModelIndex();
+ bool isModelProxy = qobject_cast<const QAndroidItemModelProxy *>(modelIndex.model());
+ if (isModelProxy)
+ return JQtModelIndex(modelIndex.row(), modelIndex.column(), modelIndex.internalId(),
+ reinterpret_cast<jlong>(modelIndex.model()));
+ else
+ return JQtModelIndex(modelIndex.row(), modelIndex.column(),
+ QAndroidModelIndexProxy::jInstance(modelIndex.parent()),
+ reinterpret_cast<jlong>(modelIndex.model()));
+}
+
+jobject QAndroidModelIndexProxy::data(JNIEnv *env, jobject object, int role)
+{
+ Q_ASSERT(env);
+ Q_ASSERT(object);
+
+ QModelIndex modelIndex = qInstance(object);
+ if (!modelIndex.isValid())
+ return nullptr;
+
+ return QAndroidTypeConverter::toJavaObject(modelIndex.model()->data(modelIndex, role), env);
+}
+
+jlong QAndroidModelIndexProxy::internalId(JNIEnv *env, jobject object)
+{
+ Q_ASSERT(env);
+ Q_ASSERT(object);
+ return qInstance(object).internalId();
+};
+
+jboolean QAndroidModelIndexProxy::isValid(JNIEnv *env, jobject object)
+{
+ Q_ASSERT(env);
+ Q_ASSERT(object);
+ return qInstance(object).isValid();
+}
+
+JQtModelIndex QAndroidModelIndexProxy::parent(JNIEnv *env, jobject object)
+{
+ Q_ASSERT(env);
+ Q_ASSERT(object);
+ return jInstance(qInstance(object).parent());
+};
+
+bool QAndroidModelIndexProxy::registerNatives(QJniEnvironment &env)
+{
+ return env.registerNativeMethods(
+ Traits<JQtModelIndex>::className(),
+ { Q_JNI_NATIVE_SCOPED_METHOD(data, QAndroidModelIndexProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(internalId, QAndroidModelIndexProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(isValid, QAndroidModelIndexProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(parent, QAndroidModelIndexProxy) });
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/platform/android/qandroidmodelindexproxy_p.h b/src/quick/platform/android/qandroidmodelindexproxy_p.h
new file mode 100644
index 0000000000..05db788652
--- /dev/null
+++ b/src/quick/platform/android/qandroidmodelindexproxy_p.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QANDROIDMODELINDEXPROXY_P_H
+#define QANDROIDMODELINDEXPROXY_P_H
+
+#include <QtQuick/private/qandroidtypes_p.h>
+#include <QtQuick/private/qtquickglobal_p.h>
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjnitypes.h>
+#include <QDebug>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtJniTypes;
+
+class QAndroidItemModelProxy;
+
+class Q_QUICK_EXPORT QAndroidModelIndexProxy
+{
+public:
+ static JQtModelIndex jInstance(QModelIndex modelIndex);
+ static QModelIndex qInstance(JQtModelIndex jModelIndex);
+
+ static jobject data(JNIEnv *env, jobject object, int role);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(data)
+
+ static jlong internalId(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(internalId)
+
+ static jboolean isValid(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(isValid)
+
+ static JQtModelIndex parent(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(parent)
+
+ static bool registerNatives(QJniEnvironment &env);
+};
+
+QT_BEGIN_NAMESPACE
+
+#endif // QANDROIDMODELINDEXPROXY_P_H
diff --git a/src/quick/platform/android/qandroidquickviewembedding.cpp b/src/quick/platform/android/qandroidquickviewembedding.cpp
index 8b25ff0deb..e7932d80ae 100644
--- a/src/quick/platform/android/qandroidquickviewembedding.cpp
+++ b/src/quick/platform/android/qandroidquickviewembedding.cpp
@@ -2,6 +2,11 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtQuick/private/qandroidquickviewembedding_p.h>
+#include <QtQuick/private/qandroidtypes_p.h>
+#include <QtQuick/private/qandroidtypeconverter_p.h>
+#include <QtQuick/private/qandroidviewsignalmanager_p.h>
+#include <QtQuick/private/qandroiditemmodelproxy_p.h>
+#include <QtQuick/private/qandroidmodelindexproxy_p.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qjnienvironment.h>
@@ -18,18 +23,13 @@ Q_DECLARE_JNI_CLASS(QtQuickView, "org/qtproject/qt/android/QtQuickView");
Q_DECLARE_JNI_CLASS(QtWindow, "org/qtproject/qt/android/QtWindow");
Q_DECLARE_JNI_CLASS(View, "android/view/View");
-Q_DECLARE_JNI_CLASS(Void, "java/lang/Void");
-Q_DECLARE_JNI_CLASS(Integer, "java/lang/Integer");
-Q_DECLARE_JNI_CLASS(Double, "java/lang/Double");
-Q_DECLARE_JNI_CLASS(Float, "java/lang/Float");
-Q_DECLARE_JNI_CLASS(Boolean, "java/lang/Boolean");
-Q_DECLARE_JNI_CLASS(String, "java/lang/String");
-Q_DECLARE_JNI_CLASS(Class, "java/lang/Class");
-
namespace QtAndroidQuickViewEmbedding
{
- void createQuickView(JNIEnv*, jobject nativeWindow, jstring qmlUri, jint width, jint height,
- jlong parentWindowReference, QtJniTypes::StringArray qmlImportPaths)
+ constexpr const char *uninitializedViewMessage = "because QtQuickView is not loaded or ready yet.";
+
+ void createQuickView(JNIEnv *, jobject nativeWindow, jstring qmlUri, jint width, jint height,
+ jlong parentWindowReference, jlong viewReference,
+ QtJniTypes::StringArray qmlImportPaths)
{
static_assert (sizeof(jlong) >= sizeof(void*),
"Insufficient size of Java type to hold the c++ pointer");
@@ -45,43 +45,56 @@ namespace QtAndroidQuickViewEmbedding
QMetaObject::invokeMethod(qApp, [qtViewObject = QJniObject(nativeWindow),
parentWindowReference,
+ viewReference,
width,
height,
qmlUrl,
importPaths] {
- QWindow *parentWindow = reinterpret_cast<QWindow *>(parentWindowReference);
- QQuickView *view = new QQuickView(parentWindow);
- QQmlEngine *engine = view->engine();
- new SignalHelper(view);
- QObject::connect(view, &QQuickView::statusChanged,
- [qtViewObject](QQuickView::Status status) {
- qtViewObject.callMethod<void>("handleStatusChange", status);
- });
- view->setResizeMode(QQuickView::SizeRootObjectToView);
- view->setColor(QColor(Qt::transparent));
- view->setWidth(width);
- view->setHeight(height);
- for (const QString &path : importPaths)
- engine->addImportPath(path);
-
- const QtJniTypes::QtWindow window = reinterpret_cast<jobject>(view->winId());
- qtViewObject.callMethod<void>("addQtWindow",
- window,
- reinterpret_cast<jlong>(view),
- parentWindowReference);
+ // If the view does not exists (viewReference==0) we should create and set it up.
+ // Else we only reset the source of the view.
+ QAndroidQuickView *view = reinterpret_cast<QAndroidQuickView *>(viewReference);
+ if (!view) {
+ QWindow *parentWindow = reinterpret_cast<QWindow *>(parentWindowReference);
+ view = new QAndroidQuickView(parentWindow);
+ QObject::connect(view, &QAndroidQuickView::statusChanged, view,
+ [qtViewObject](QAndroidQuickView::Status status) {
+ qtViewObject.callMethod<void>("handleStatusChange", status);
+ });
+ view->setResizeMode(QAndroidQuickView::SizeRootObjectToView);
+ view->setColor(QColor(Qt::transparent));
+ view->setWidth(width);
+ view->setHeight(height);
+ QQmlEngine *engine = view->engine();
+ for (const QString &path : importPaths)
+ engine->addImportPath(path);
+
+ const QtJniTypes::QtWindow window = reinterpret_cast<jobject>(view->winId());
+ qtViewObject.callMethod<void>("addQtWindow",
+ window,
+ reinterpret_cast<jlong>(view),
+ parentWindowReference);
+ }
view->setSource(qmlUrl);
});
}
+ std::pair<QAndroidQuickView *, QQuickItem *> getViewAndRootObject(jlong windowReference)
+ {
+ QAndroidQuickView *view = reinterpret_cast<QAndroidQuickView *>(windowReference);
+ QQuickItem *rootObject = Q_LIKELY(view) ? view->rootObject() : nullptr;
+ return std::make_pair(view, rootObject);
+ }
+
void setRootObjectProperty(JNIEnv *env, jobject object, jlong windowReference,
jstring propertyName, jobject value)
{
Q_UNUSED(env);
Q_UNUSED(object);
- QQuickItem *rootObject = reinterpret_cast<QQuickView *>(windowReference)->rootObject();
+ auto [_, rootObject] = getViewAndRootObject(windowReference);
if (!rootObject) {
- qWarning() << "QtQuickView instance does not own a root object.";
+ qWarning("Cannot set property %s %s", qPrintable(QJniObject(propertyName).toString()),
+ uninitializedViewMessage);
return;
}
@@ -95,20 +108,14 @@ namespace QtAndroidQuickViewEmbedding
QMetaProperty metaProperty = rootMetaObject->property(propertyIndex);
const QJniObject propertyValue(value);
- const QByteArray valueClassname = propertyValue.className();
-
- if (valueClassname == QtJniTypes::Traits<QtJniTypes::String>::className())
- metaProperty.write(rootObject, propertyValue.toString());
- else if (valueClassname == QtJniTypes::Traits<QtJniTypes::Integer>::className())
- metaProperty.write(rootObject, propertyValue.callMethod<jint>("intValue"));
- else if (valueClassname == QtJniTypes::Traits<QtJniTypes::Double>::className())
- metaProperty.write(rootObject, propertyValue.callMethod<jdouble>("doubleValue"));
- else if (valueClassname == QtJniTypes::Traits<QtJniTypes::Float>::className())
- metaProperty.write(rootObject, propertyValue.callMethod<jfloat>("floatValue"));
- else if (valueClassname == QtJniTypes::Traits<QtJniTypes::Boolean>::className())
- metaProperty.write(rootObject, propertyValue.callMethod<jboolean>("booleanValue"));
- else
- qWarning("Setting the property type of %s is not supported.", valueClassname.data());
+ const QVariant variantToWrite = QAndroidTypeConverter::toQVariant(propertyValue);
+
+ if (!variantToWrite.isValid()) {
+ qWarning("Setting the property type of %s is not supported.",
+ qPrintable(propertyValue.className()));
+ } else {
+ metaProperty.write(rootObject, variantToWrite);
+ }
}
jobject getRootObjectProperty(JNIEnv *env, jobject object, jlong windowReference,
@@ -118,54 +125,28 @@ namespace QtAndroidQuickViewEmbedding
Q_ASSERT(env);
const QString property = QJniObject(propertyName).toString();
- QQuickView *view = reinterpret_cast<QQuickView *>(windowReference);
- QQuickItem *rootObject = view->rootObject();
+ auto [_, rootObject] = getViewAndRootObject(windowReference);
if (!rootObject) {
- qWarning("Cannot read property %s as the QtQuickView instance (%s)"
- "does not own a root object.",
- qPrintable(property),
- qPrintable(view->source().toString()));
+ qWarning("Cannot get property %s %s", qPrintable(property), uninitializedViewMessage);
return nullptr;
}
const QMetaObject *rootMetaObject = rootObject->metaObject();
int propertyIndex = rootMetaObject->indexOfProperty(property.toUtf8().constData());
if (propertyIndex < 0) {
- qWarning("Cannot read property %s as it does not exist in the root QML object.",
+ qWarning("Cannot get property %s as it does not exist in the root QML object.",
qPrintable(property));
return nullptr;
}
QMetaProperty metaProperty = rootMetaObject->property(propertyIndex);
- QVariant propertyValue = metaProperty.read(rootObject);
- const int propertyTypeId = propertyValue.typeId();
-
- switch (propertyTypeId) {
- case QMetaType::Type::Int:
- return env->NewLocalRef(
- QJniObject::construct<QtJniTypes::Integer>(get<int>(std::move(propertyValue)))
- .object());
- case QMetaType::Type::Double:
- return env->NewLocalRef(
- QJniObject::construct<QtJniTypes::Double>(get<double>(std::move(propertyValue)))
- .object());
- case QMetaType::Type::Float:
- return env->NewLocalRef(
- QJniObject::construct<QtJniTypes::Float>(get<float>(std::move(propertyValue)))
- .object());
- case QMetaType::Type::Bool:
- return env->NewLocalRef(
- QJniObject::construct<QtJniTypes::Boolean>(get<bool>(std::move(propertyValue)))
- .object());
- case QMetaType::Type::QString:
- return env->NewLocalRef(
- QJniObject::fromString(get<QString>(std::move(propertyValue))).object());
- default:
+ const QVariant propertyValue = metaProperty.read(rootObject);
+ jobject jObject = QAndroidTypeConverter::toJavaObject(propertyValue, env);
+ if (!jObject) {
qWarning("Property %s cannot be converted to a supported Java data type.",
qPrintable(property));
}
-
- return nullptr;
+ return jObject;
}
int addRootObjectSignalListener(JNIEnv *env, jobject, jlong windowReference, jstring signalName,
@@ -181,18 +162,14 @@ namespace QtAndroidQuickViewEmbedding
{ "java/lang/Boolean", QMetaType::Type::Bool }
};
- QQuickView *view = reinterpret_cast<QQuickView *>(windowReference);
- if (!view) {
- qWarning() << "QtQuickView is not loaded or ready yet.";
- return -1;
- }
- QQuickItem *rootObject = view->rootObject();
+ auto [view, rootObject] = getViewAndRootObject(windowReference);
if (!rootObject) {
- qWarning() << "QtQuickView instance does not own a root object.";
+ qWarning("Cannot connect to signal %s %s",
+ qPrintable(QJniObject(signalName).toString()), uninitializedViewMessage);
return -1;
}
- SignalHelper *signalHelper = view->findChild<SignalHelper *>();
+ QAndroidViewSignalManager *signalManager = view->signalManager();
const QByteArray javaArgClass = QJniObject(argType).className();
const char *qArgName =
QMetaType(javaToQMetaType.value(javaArgClass, QMetaType::Type::UnknownType)).name();
@@ -231,7 +208,7 @@ namespace QtAndroidQuickViewEmbedding
if (signalIndex == -1)
return -1;
- const QMetaObject *helperMetaObject = signalHelper->metaObject();
+ const QMetaObject *helperMetaObject = signalManager->metaObject();
QByteArray helperSignalSignature = signalSignature;
helperSignalSignature.replace(0, signalSignature.indexOf('('), "forwardSignal");
int helperSlotIndex = helperMetaObject->indexOfSlot(helperSignalSignature.constData());
@@ -240,15 +217,17 @@ namespace QtAndroidQuickViewEmbedding
// Return the id if the signal is already connected to the same listener.
QJniObject listenerJniObject(listener);
- if (signalHelper->listenersMap.contains(signalSignature)) {
- auto listenerInfos = signalHelper->listenersMap.values(signalSignature);
- auto isSameListener = [listenerJniObject](const SignalHelper::ListenerInfo &listenerInfo) {
- return listenerInfo.listener == listenerJniObject;
- };
- auto iterator = std::find_if(listenerInfos.constBegin(),
- listenerInfos.constEnd(),
+ if (signalManager->connectionInfoMap.contains(signalSignature)) {
+ auto connectionInfos = signalManager->connectionInfoMap.values(signalSignature);
+ auto isSameListener =
+ [listenerJniObject](
+ const QAndroidViewSignalManager::ConnectionInfo &connectionInfo) {
+ return connectionInfo.listener == listenerJniObject;
+ };
+ auto iterator = std::find_if(connectionInfos.constBegin(),
+ connectionInfos.constEnd(),
isSameListener);
- if (iterator != listenerInfos.end()) {
+ if (iterator != connectionInfos.end()) {
qWarning("Signal listener with the ID of %i is already connected to %s signal.",
iterator->id,
signalSignature.constData());
@@ -258,52 +237,52 @@ namespace QtAndroidQuickViewEmbedding
QMetaMethod signalMethod = metaObject->method(signalIndex);
QMetaMethod signalForwarderMethod = helperMetaObject->method(helperSlotIndex);
- signalHelper->connectionHandleCounter++;
+ signalManager->connectionHandleCounter++;
QMetaObject::Connection connection;
- if (signalHelper->listenersMap.contains(signalSignature)) {
- connection = signalHelper
- ->connections[signalHelper->listenersMap.value(signalSignature).id];
+ if (signalManager->connectionInfoMap.contains(signalSignature)) {
+ const int existingId = signalManager->connectionInfoMap.value(signalSignature).id;
+ connection = signalManager->connections[existingId];
} else {
connection = QObject::connect(rootObject,
signalMethod,
- signalHelper,
+ signalManager,
signalForwarderMethod);
}
- SignalHelper::ListenerInfo listenerInfo;
- listenerInfo.listener = listenerJniObject;
- listenerInfo.javaArgType = javaArgClass;
- listenerInfo.propertyIndex = propertyIndex;
- listenerInfo.signalSignature = signalSignature;
- listenerInfo.id = signalHelper->connectionHandleCounter;
+ QAndroidViewSignalManager::ConnectionInfo connectionInfo;
+ connectionInfo.listener = listenerJniObject;
+ connectionInfo.javaArgType = javaArgClass;
+ connectionInfo.propertyIndex = propertyIndex;
+ connectionInfo.signalSignature = signalSignature;
+ connectionInfo.id = signalManager->connectionHandleCounter;
- signalHelper->listenersMap.insert(signalSignature, listenerInfo);
- signalHelper->connections.insert(listenerInfo.id, connection);
+ signalManager->connectionInfoMap.insert(signalSignature, connectionInfo);
+ signalManager->connections.insert(connectionInfo.id, connection);
- return listenerInfo.id;
+ return connectionInfo.id;
}
bool removeRootObjectSignalListener(JNIEnv *, jobject, jlong windowReference,
jint signalListenerId)
{
- QQuickView *view = reinterpret_cast<QQuickView *>(windowReference);
- QQuickItem *rootObject = view->rootObject();
+ auto [view, rootObject] = getViewAndRootObject(windowReference);
if (!rootObject) {
- qWarning() << "QtQuickView instance does not own a root object.";
+ qWarning("Cannot disconnect the signal connection with id: %i %s", signalListenerId,
+ uninitializedViewMessage);
return false;
}
- SignalHelper *signalHelper = view->findChild<SignalHelper *>();
- if (!signalHelper->connections.contains(signalListenerId))
+ QAndroidViewSignalManager *signalManager = view->signalManager();
+ if (!signalManager->connections.contains(signalListenerId))
return false;
QByteArray signalSignature;
- for (auto listenerInfoIter = signalHelper->listenersMap.begin();
- listenerInfoIter != signalHelper->listenersMap.end();) {
+ for (auto listenerInfoIter = signalManager->connectionInfoMap.begin();
+ listenerInfoIter != signalManager->connectionInfoMap.end();) {
if (listenerInfoIter->id == signalListenerId) {
signalSignature = listenerInfoIter->signalSignature;
- signalHelper->listenersMap.erase(listenerInfoIter);
+ signalManager->connectionInfoMap.erase(listenerInfoIter);
break;
} else {
++listenerInfoIter;
@@ -311,98 +290,13 @@ namespace QtAndroidQuickViewEmbedding
}
// disconnect if its the last listener associated with the signal signatures
- if (!signalHelper->listenersMap.contains(signalSignature))
- rootObject->disconnect(signalHelper->connections.value(signalListenerId));
+ if (!signalManager->connectionInfoMap.contains(signalSignature))
+ rootObject->disconnect(signalManager->connections.value(signalListenerId));
- signalHelper->connections.remove(signalListenerId);
+ signalManager->connections.remove(signalListenerId);
return true;
}
- void SignalHelper::forwardSignal()
- {
- invokeListener(sender(), senderSignalIndex(), QVariant());
- }
-
- void SignalHelper::forwardSignal(int signalValue)
- {
- invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
- }
-
- void SignalHelper::forwardSignal(bool signalValue)
- {
- invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
- }
-
- void SignalHelper::forwardSignal(double signalValue)
- {
- invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
- }
-
- void SignalHelper::forwardSignal(float signalValue)
- {
- invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
- }
-
- void SignalHelper::forwardSignal(QString signalValue)
- {
- invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
- }
-
- void SignalHelper::invokeListener(QObject *sender, int senderSignalIndex, QVariant signalValue)
- {
- using namespace QtJniTypes;
-
- const QMetaObject *metaObject = sender->metaObject();
- const QMetaMethod signalMethod = metaObject->method(senderSignalIndex);
-
- for (auto listenerInfoIter = listenersMap.constFind(signalMethod.methodSignature());
- listenerInfoIter != listenersMap.constEnd() &&
- listenerInfoIter.key() == signalMethod.methodSignature();
- ++listenerInfoIter) {
- const ListenerInfo listenerInfo = *listenerInfoIter;
- const QByteArray javaArgType = listenerInfo.javaArgType;
- QJniObject jSignalMethodName =
- QJniObject::fromString(QLatin1StringView(signalMethod.name()));
-
- if (listenerInfo.propertyIndex != -1 && javaArgType != Traits<Void>::className())
- signalValue = metaObject->property(listenerInfo.propertyIndex).read(sender);
-
- int valueTypeId = signalValue.typeId();
- QJniObject jValue;
-
- switch (valueTypeId) {
- case QMetaType::Type::UnknownType:
- break;
- case QMetaType::Type::Int:
- jValue = qVariantToJniObject<Integer,jint>(signalValue);
- break;
- case QMetaType::Type::Double:
- jValue = qVariantToJniObject<Double,jdouble>(signalValue);
- break;
- case QMetaType::Type::Float:
- jValue = qVariantToJniObject<Float,jfloat>(signalValue);
- break;
- case QMetaType::Type::Bool:
- jValue = qVariantToJniObject<Boolean,jboolean>(signalValue);
- break;
- case QMetaType::Type::QString:
- jValue = QJniObject::fromString(get<QString>(std::move(signalValue)));
- break;
- default:
- qWarning("Mismatching argument types between QML signal (%s) and the Java function "
- "(%s). Sending null as argument.",
- signalMethod.methodSignature().constData(), javaArgType.constData());
- }
-
- QNativeInterface::QAndroidApplication::runOnAndroidMainThread(
- [listenerInfo, jSignalMethodName, jValue]() {
- listenerInfo.listener.callMethod<void, jstring, jobject>("onSignalEmitted",
- jSignalMethodName.object<jstring>(),
- jValue.object());
- });
- }
- }
-
bool registerNatives(QJniEnvironment& env) {
return env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtQuickView>::className(),
{Q_JNI_NATIVE_SCOPED_METHOD(createQuickView,
@@ -433,6 +327,12 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
return JNI_ERR;
if (!QtAndroidQuickViewEmbedding::registerNatives(env))
return JNI_ERR;
+ if (!QAndroidItemModelProxy::registerAbstractNatives(env))
+ return JNI_ERR;
+ if (!QAndroidItemModelProxy::registerProxyNatives(env))
+ return JNI_ERR;
+ if (!QAndroidModelIndexProxy::registerNatives(env))
+ return JNI_ERR;
return JNI_VERSION_1_6;
}
diff --git a/src/quick/platform/android/qandroidquickviewembedding_p.h b/src/quick/platform/android/qandroidquickviewembedding_p.h
index ace387a7f1..9c5e4a75ed 100644
--- a/src/quick/platform/android/qandroidquickviewembedding_p.h
+++ b/src/quick/platform/android/qandroidquickviewembedding_p.h
@@ -15,6 +15,8 @@
// We mean it.
//
+#include <QtQuick/private/qandroidviewsignalmanager_p.h>
+
#include <QtCore/qjnienvironment.h>
#include <QtCore/qjnitypes.h>
#include <QtQuick/qquickview.h>
@@ -27,7 +29,8 @@ namespace QtAndroidQuickViewEmbedding
{
bool registerNatives(QJniEnvironment& env);
void createQuickView(JNIEnv *env, jobject nativeWindow, jstring qmlUri, jint width, jint height,
- jlong parentWindowReference, QtJniTypes::StringArray qmlImportPaths);
+ jlong parentWindowReference, jlong viewReference,
+ QtJniTypes::StringArray qmlImportPaths);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(createQuickView)
void setRootObjectProperty(JNIEnv *env, jobject, jlong parentWindowReference,
jstring propertyName, jobject value);
@@ -42,38 +45,17 @@ namespace QtAndroidQuickViewEmbedding
jint signalListenerId);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(removeRootObjectSignalListener)
- class SignalHelper : public QObject
+ class QAndroidQuickView : public QQuickView
{
Q_OBJECT
+ std::unique_ptr<QAndroidViewSignalManager> m_signalManager;
+
public:
- struct ListenerInfo
+ explicit QAndroidQuickView(QWindow *parent)
+ : QQuickView(parent), m_signalManager(new QAndroidViewSignalManager())
{
- ListenerInfo() : propertyIndex(-1) { }
- int id;
- QJniObject listener;
- QByteArray javaArgType;
- QByteArray signalSignature;
- int propertyIndex;
- };
-
- int connectionHandleCounter;
- explicit SignalHelper(QQuickView *parent) : QObject(parent), connectionHandleCounter(0) { }
- QMultiMap<QByteArray, ListenerInfo> listenersMap;
- QHash<int, QMetaObject::Connection> connections;
- void invokeListener(QObject *sender, int senderSignalIndex, QVariant signalValue);
-
- template<typename JT, typename T>
- inline QJniObject qVariantToJniObject(const QVariant& v) {
- return QJniObject(QtJniTypes::Traits<JT>::className(), get<T>(std::move(v)));
- };
-
- public slots:
- void forwardSignal();
- void forwardSignal(int);
- void forwardSignal(double);
- void forwardSignal(float);
- void forwardSignal(bool);
- void forwardSignal(QString);
+ }
+ inline QAndroidViewSignalManager *signalManager() const { return m_signalManager.get(); };
};
};
diff --git a/src/quick/platform/android/qandroidtypeconverter_p.h b/src/quick/platform/android/qandroidtypeconverter_p.h
new file mode 100644
index 0000000000..1bde5a5464
--- /dev/null
+++ b/src/quick/platform/android/qandroidtypeconverter_p.h
@@ -0,0 +1,99 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QANDROIDTYPECONVERTER_P_H
+#define QANDROIDTYPECONVERTER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#include <QtQuick/private/qandroidtypes_p.h>
+#include <QtQuick/private/qandroiditemmodelproxy_p.h>
+
+#include <QtCore/qjniobject.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjnitypes.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QAndroidTypeConverter
+{
+ [[maybe_unused]] static QVariant toQVariant(const QJniObject &object)
+ {
+ using namespace QtJniTypes;
+ if (!object.isValid())
+ return QVariant{};
+ const QByteArray classname(object.className());
+
+ if (classname == Traits<String>::className())
+ return object.toString();
+ else if (classname == Traits<Integer>::className())
+ return object.callMethod<jint>("intValue");
+ else if (classname == Traits<Long>::className())
+ return QVariant::fromValue<long>(object.callMethod<jlong>("longValue"));
+ else if (classname == Traits<Double>::className())
+ return object.callMethod<jdouble>("doubleValue");
+ else if (classname == Traits<Float>::className())
+ return object.callMethod<jfloat>("floatValue");
+ else if (classname == Traits<Boolean>::className())
+ return QVariant::fromValue<bool>(object.callMethod<jboolean>("booleanValue"));
+ else {
+ QJniEnvironment env;
+ const jclass className = env.findClass(Traits<JQtAbstractItemModel>::className());
+ if (env->IsInstanceOf(object.object(), className))
+ return QVariant::fromValue(QAndroidItemModelProxy::createNativeProxy(object));
+ }
+
+ return QVariant{};
+ }
+
+ [[maybe_unused]] Q_REQUIRED_RESULT static jobject toJavaObject(const QVariant &var, JNIEnv *env)
+ {
+ Q_ASSERT(env);
+ switch (var.typeId()) {
+ case QMetaType::Type::Int:
+ return env->NewLocalRef(QJniObject::construct<QtJniTypes::Integer>(
+ get<int>(var))
+ .object());
+ case QMetaType::Type::Long:
+ case QMetaType::Type::LongLong:
+ return env->NewLocalRef(QJniObject::construct<QtJniTypes::Long>(
+ get<jlong>(var))
+ .object());
+ case QMetaType::Type::Double:
+ return env->NewLocalRef(QJniObject::construct<QtJniTypes::Double>(
+ get<double>(var))
+ .object());
+ case QMetaType::Type::Float:
+ return env->NewLocalRef(QJniObject::construct<QtJniTypes::Float>(
+ get<float>(var))
+ .object());
+ case QMetaType::Type::Bool:
+ return env->NewLocalRef(QJniObject::construct<QtJniTypes::Boolean>(
+ get<bool>(var))
+ .object());
+ case QMetaType::Type::QString:
+ return env->NewLocalRef(
+ QJniObject::fromString(get<QString>(var)).object());
+ default:
+ if (var.canConvert<QAbstractItemModel *>()) {
+ return env->NewLocalRef(
+ QAndroidItemModelProxy::createProxy(var.value<QAbstractItemModel *>())
+ .object());
+ } else
+ return nullptr;
+ }
+ return nullptr;
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDTYPECONVERTER_P_H
diff --git a/src/quick/platform/android/qandroidtypes_p.h b/src/quick/platform/android/qandroidtypes_p.h
new file mode 100644
index 0000000000..b2ac74c90e
--- /dev/null
+++ b/src/quick/platform/android/qandroidtypes_p.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QANDROIDTYPES_P_H
+#define QANDROIDTYPES_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#include <QtCore/qjniobject.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjnitypes.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_JNI_CLASS(Void, "java/lang/Void");
+Q_DECLARE_JNI_CLASS(Integer, "java/lang/Integer");
+Q_DECLARE_JNI_CLASS(Long, "java/lang/Long");
+Q_DECLARE_JNI_CLASS(Double, "java/lang/Double");
+Q_DECLARE_JNI_CLASS(Float, "java/lang/Float");
+Q_DECLARE_JNI_CLASS(Boolean, "java/lang/Boolean");
+Q_DECLARE_JNI_CLASS(String, "java/lang/String");
+Q_DECLARE_JNI_CLASS(Class, "java/lang/Class");
+
+Q_DECLARE_JNI_CLASS(JQtAbstractItemModel, "org/qtproject/qt/android/QtAbstractItemModel")
+Q_DECLARE_JNI_CLASS(JQtAndroidItemModelProxy, "org/qtproject/qt/android/QtAndroidItemModelProxy")
+Q_DECLARE_JNI_CLASS(JQtModelIndex, "org/qtproject/qt/android/QtModelIndex")
+Q_DECLARE_JNI_CLASS(JHashMap, "java/util/HashMap")
+Q_DECLARE_JNI_CLASS(JSet, "java/util/Set")
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDTYPES_P_H
diff --git a/src/quick/platform/android/qandroidviewsignalmanager.cpp b/src/quick/platform/android/qandroidviewsignalmanager.cpp
new file mode 100644
index 0000000000..9fb5fc4ec5
--- /dev/null
+++ b/src/quick/platform/android/qandroidviewsignalmanager.cpp
@@ -0,0 +1,77 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtQuick/private/qandroidtypeconverter_p.h>
+#include <QtQuick/private/qandroidviewsignalmanager_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QAndroidViewSignalManager::forwardSignal()
+{
+ invokeListener(sender(), senderSignalIndex(), QVariant());
+}
+
+void QAndroidViewSignalManager::forwardSignal(int signalValue)
+{
+ invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
+}
+
+void QAndroidViewSignalManager::forwardSignal(bool signalValue)
+{
+ invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
+}
+
+void QAndroidViewSignalManager::forwardSignal(double signalValue)
+{
+ invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
+}
+
+void QAndroidViewSignalManager::forwardSignal(float signalValue)
+{
+ invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
+}
+
+void QAndroidViewSignalManager::forwardSignal(QString signalValue)
+{
+ invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
+}
+
+void QAndroidViewSignalManager::invokeListener(QObject *sender, int senderSignalIndex,
+ QVariant signalValue)
+{
+ using namespace QtJniTypes;
+
+ const QMetaObject *metaObject = sender->metaObject();
+ const QMetaMethod signalMethod = metaObject->method(senderSignalIndex);
+
+ for (auto connectionInfoIter = connectionInfoMap.constFind(signalMethod.methodSignature());
+ connectionInfoIter != connectionInfoMap.constEnd()
+ && connectionInfoIter.key() == signalMethod.methodSignature();
+ ++connectionInfoIter) {
+ const ConnectionInfo connectionInfo = *connectionInfoIter;
+ const QByteArray javaArgType = connectionInfo.javaArgType;
+ QJniObject jSignalMethodName =
+ QJniObject::fromString(QLatin1StringView(signalMethod.name()));
+
+ if (connectionInfo.propertyIndex != -1 && javaArgType != Traits<Void>::className())
+ signalValue = metaObject->property(connectionInfo.propertyIndex).read(sender);
+
+ QJniObject jValue(
+ QAndroidTypeConverter::toJavaObject(signalValue, QJniEnvironment::getJniEnv()));
+
+ if (!jValue.isValid()) {
+ qWarning("Mismatching argument types between QML signal (%s) and the Java function "
+ "(%s). Sending null as argument.",
+ signalMethod.methodSignature().constData(), javaArgType.constData());
+ }
+
+ QNativeInterface::QAndroidApplication::runOnAndroidMainThread(
+ [connectionInfo, jSignalMethodName, jValue]() {
+ connectionInfo.listener.callMethod<void, jstring, jobject>(
+ "onSignalEmitted", jSignalMethodName.object<jstring>(),
+ jValue.object());
+ });
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/platform/android/qandroidviewsignalmanager_p.h b/src/quick/platform/android/qandroidviewsignalmanager_p.h
new file mode 100644
index 0000000000..c6ca6543b3
--- /dev/null
+++ b/src/quick/platform/android/qandroidviewsignalmanager_p.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QANDROIDVIEWSIGNALMANAGER_P_H
+#define QANDROIDVIEWSIGNALMANAGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qobject.h>
+#include <QtCore/qjnitypes.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidViewSignalManager : public QObject
+{
+ Q_OBJECT
+public:
+ struct ConnectionInfo
+ {
+ int id;
+ QJniObject listener;
+ QByteArray javaArgType;
+ QByteArray signalSignature;
+ int propertyIndex{ -1 };
+ };
+
+ explicit QAndroidViewSignalManager()
+ : QObject(), connectionHandleCounter(0)
+ {
+ }
+ void invokeListener(QObject *sender, int senderSignalIndex, QVariant signalValue);
+
+ int connectionHandleCounter;
+ QMultiMap<QByteArray, ConnectionInfo> connectionInfoMap;
+ QHash<int, QMetaObject::Connection> connections;
+
+public slots:
+ void forwardSignal();
+ void forwardSignal(int);
+ void forwardSignal(double);
+ void forwardSignal(float);
+ void forwardSignal(bool);
+ void forwardSignal(QString);
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDVIEWSIGNALMANAGER_P_H
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 5746d984bf..6c084ec441 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -2710,6 +2710,8 @@ bool Renderer::ensurePipelineState(Element *e, const ShaderManager::Shader *sms,
blend.dstColor = m_gstate.dstColor;
blend.srcAlpha = m_gstate.srcAlpha;
blend.dstAlpha = m_gstate.dstAlpha;
+ blend.opColor = m_gstate.opColor;
+ blend.opAlpha = m_gstate.opAlpha;
ps->setTargetBlends({ blend });
ps->setDepthTest(m_gstate.depthTest);
@@ -2841,6 +2843,7 @@ static void rendererToMaterialGraphicsState(QSGMaterialShader::GraphicsPipelineS
// the enum values should match, sanity check it
Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::OneMinusSrc1Alpha) == int(QRhiGraphicsPipeline::OneMinusSrc1Alpha));
+ Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::BlendOpMax) == int(QRhiGraphicsPipeline::Max));
Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::A) == int(QRhiGraphicsPipeline::A));
Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::CullBack) == int(QRhiGraphicsPipeline::Back));
Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::Line) == int(QRhiGraphicsPipeline::Line));
@@ -2858,6 +2861,9 @@ static void rendererToMaterialGraphicsState(QSGMaterialShader::GraphicsPipelineS
dst->srcAlpha = QSGMaterialShader::GraphicsPipelineState::BlendFactor(src->srcAlpha);
dst->dstAlpha = QSGMaterialShader::GraphicsPipelineState::BlendFactor(src->dstAlpha);
+ dst->opColor = QSGMaterialShader::GraphicsPipelineState::BlendOp(src->opColor);
+ dst->opAlpha = QSGMaterialShader::GraphicsPipelineState::BlendOp(src->opAlpha);
+
dst->colorWrite = QSGMaterialShader::GraphicsPipelineState::ColorMask(int(src->colorWrite));
dst->cullMode = QSGMaterialShader::GraphicsPipelineState::CullMode(src->cullMode);
@@ -2877,6 +2883,8 @@ static void materialToRendererGraphicsState(GraphicsState *dst,
dst->srcAlpha = dst->srcColor;
dst->dstAlpha = dst->dstColor;
}
+ dst->opColor = QRhiGraphicsPipeline::BlendOp(src->opColor);
+ dst->opAlpha = QRhiGraphicsPipeline::BlendOp(src->opAlpha);
dst->colorWrite = QRhiGraphicsPipeline::ColorMask(int(src->colorWrite));
dst->cullMode = QRhiGraphicsPipeline::CullMode(src->cullMode);
dst->polygonMode = QRhiGraphicsPipeline::PolygonMode(src->polygonMode);
@@ -4141,6 +4149,8 @@ bool operator==(const GraphicsState &a, const GraphicsState &b) noexcept
&& a.dstColor == b.dstColor
&& a.srcAlpha == b.srcAlpha
&& a.dstAlpha == b.dstAlpha
+ && a.opColor == b.opColor
+ && a.opAlpha == b.opAlpha
&& a.colorWrite == b.colorWrite
&& a.cullMode == b.cullMode
&& a.usesScissor == b.usesScissor
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index a84797a4c6..11cec6b99b 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -599,6 +599,8 @@ struct GraphicsState
QRhiGraphicsPipeline::BlendFactor dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
QRhiGraphicsPipeline::BlendFactor srcAlpha = QRhiGraphicsPipeline::One;
QRhiGraphicsPipeline::BlendFactor dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
+ QRhiGraphicsPipeline::BlendOp opColor = QRhiGraphicsPipeline::Add;
+ QRhiGraphicsPipeline::BlendOp opAlpha = QRhiGraphicsPipeline::Add;
QRhiGraphicsPipeline::ColorMask colorWrite = QRhiGraphicsPipeline::ColorMask(0xF);
QRhiGraphicsPipeline::CullMode cullMode = QRhiGraphicsPipeline::None;
bool usesScissor = false;
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
index 49508c1c35..e2b240479e 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -414,10 +414,11 @@ int QSGMaterial::compare(const QSGMaterial *other) const
See \l QRhi::MultiView, \l QRhiColorAttachment::setMultiViewCount(), and
\l QRhiGraphicsPipeline::setMultiViewCount() for further, lower-level details
on multiview support in Qt. The Qt Quick scene graph renderer is prepared to
- recognize multiview render targets, when specified via
- \l QQuickRenderTarget::fromRhiRenderTarget() or the \c MultiView
- functions such as \l{QQuickRenderTarget::}{fromVulkanImageMultiView()}, and
- propagate the view count to graphics pipelines and the materials.
+ recognize multiview render targets, when specified via \l
+ QQuickRenderTarget::fromRhiRenderTarget() or the 3D API specific functions,
+ such as \l{QQuickRenderTarget::}{fromVulkanImage()} with an \c arraySize
+ argument greater than 1. The renderer will then propagate the view count to
+ graphics pipelines and the materials.
\since 6.8
*/
diff --git a/src/quick/scenegraph/coreapi/qsgmaterialshader.cpp b/src/quick/scenegraph/coreapi/qsgmaterialshader.cpp
index a661e47765..57090f73b3 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterialshader.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterialshader.cpp
@@ -661,6 +661,17 @@ bool QSGMaterialShader::updateGraphicsPipelineState(RenderState &state, Graphics
*/
/*!
+ \enum QSGMaterialShader::GraphicsPipelineState::BlendOp
+ \since 6.8
+
+ \value BlendOpAdd
+ \value BlendOpSubtract
+ \value BlendOpReverseSubtract
+ \value BlendOpMin
+ \value BlendOpMax
+ */
+
+/*!
\enum QSGMaterialShader::GraphicsPipelineState::ColorMaskComponent
\since 5.14
@@ -772,6 +783,18 @@ bool QSGMaterialShader::updateGraphicsPipelineState(RenderState &state, Graphics
*/
/*!
+ \variable QSGMaterialShader::GraphicsPipelineState::opColor
+ \since 6.8
+ \brief RGB blending operation.
+ */
+
+/*!
+ \variable QSGMaterialShader::GraphicsPipelineState::opAlpha
+ \since 6.8
+ \brief Alpha blending operation.
+ */
+
+/*!
Returns the accumulated opacity to be used for rendering.
*/
float QSGMaterialShader::RenderState::opacity() const
diff --git a/src/quick/scenegraph/coreapi/qsgmaterialshader.h b/src/quick/scenegraph/coreapi/qsgmaterialshader.h
index 795da77477..85ebf6eb8a 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterialshader.h
+++ b/src/quick/scenegraph/coreapi/qsgmaterialshader.h
@@ -83,6 +83,14 @@ public:
OneMinusSrc1Alpha
};
+ enum BlendOp {
+ BlendOpAdd,
+ BlendOpSubtract,
+ BlendOpReverseSubtract,
+ BlendOpMin,
+ BlendOpMax
+ };
+
enum ColorMaskComponent {
R = 1 << 0,
G = 1 << 1,
@@ -112,6 +120,9 @@ public:
bool separateBlendFactors;
BlendFactor srcAlpha;
BlendFactor dstAlpha;
+ BlendOp opColor;
+ BlendOp opAlpha;
+
// This struct is extensible while keeping BC since apps only ever get
// a ptr to the struct, it is not created by them.
};
diff --git a/src/quick/scenegraph/coreapi/qsgtexture.cpp b/src/quick/scenegraph/coreapi/qsgtexture.cpp
index 57111e9e5f..08cd525a68 100644
--- a/src/quick/scenegraph/coreapi/qsgtexture.cpp
+++ b/src/quick/scenegraph/coreapi/qsgtexture.cpp
@@ -15,7 +15,7 @@
#define CAN_BACKTRACE_EXECINFO
#endif
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_APPLE)
#define CAN_BACKTRACE_EXECINFO
#endif
@@ -103,7 +103,7 @@ QSGTexturePrivate::QSGTexturePrivate(QSGTexture *t)
static int qt_debug_texture_count = 0;
-#if (defined(Q_OS_LINUX) || defined (Q_OS_MAC)) && !defined(Q_OS_ANDROID)
+#if (defined(Q_OS_LINUX) || defined (Q_OS_APPLE)) && !defined(Q_OS_ANDROID)
DEFINE_BOOL_CONFIG_OPTION(qmlDebugLeakBacktrace, QML_DEBUG_LEAK_BACKTRACE)
#define BACKTRACE_SIZE 20
diff --git a/src/quick/scenegraph/qsgcurvefillnode.cpp b/src/quick/scenegraph/qsgcurvefillnode.cpp
index 9fa526bb0a..0a4a42341e 100644
--- a/src/quick/scenegraph/qsgcurvefillnode.cpp
+++ b/src/quick/scenegraph/qsgcurvefillnode.cpp
@@ -9,6 +9,7 @@ QT_BEGIN_NAMESPACE
QSGCurveFillNode::QSGCurveFillNode()
{
setFlag(OwnsGeometry, true);
+ setFlag(UsePreprocess, true);
setGeometry(new QSGGeometry(attributes(), 0, 0));
updateMaterial();
diff --git a/src/quick/scenegraph/qsgcurvefillnode_p.cpp b/src/quick/scenegraph/qsgcurvefillnode_p.cpp
index 22cda00550..331620cf94 100644
--- a/src/quick/scenegraph/qsgcurvefillnode_p.cpp
+++ b/src/quick/scenegraph/qsgcurvefillnode_p.cpp
@@ -6,6 +6,7 @@
#include "util/qsggradientcache_p.h"
#include <private/qsgtexture_p.h>
+#include <private/qsgplaintexture_p.h>
QT_BEGIN_NAMESPACE
@@ -15,9 +16,9 @@ namespace {
{
public:
QSGCurveFillMaterialShader(QGradient::Type gradientType,
- bool includeStroke,
- bool useDerivatives,
- int viewCount);
+ bool useTextureFill,
+ bool useDerivatives,
+ int viewCount);
bool updateUniformData(RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
void updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
@@ -25,9 +26,9 @@ namespace {
};
QSGCurveFillMaterialShader::QSGCurveFillMaterialShader(QGradient::Type gradientType,
- bool includeStroke,
- bool useDerivatives,
- int viewCount)
+ bool useTextureFill,
+ bool useDerivatives,
+ int viewCount)
{
QString baseName = QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/shapecurve");
@@ -37,11 +38,10 @@ namespace {
baseName += QStringLiteral("_rg");
} else if (gradientType == QGradient::ConicalGradient) {
baseName += QStringLiteral("_cg");
+ } else if (useTextureFill) {
+ baseName += QStringLiteral("_tf");
}
- if (includeStroke)
- baseName += QStringLiteral("_stroke");
-
if (useDerivatives)
baseName += QStringLiteral("_derivatives");
@@ -50,18 +50,53 @@ namespace {
}
void QSGCurveFillMaterialShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
- QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
{
Q_UNUSED(oldMaterial);
- const QSGCurveFillMaterial *m = static_cast<QSGCurveFillMaterial *>(newMaterial);
+ QSGCurveFillMaterial *m = static_cast<QSGCurveFillMaterial *>(newMaterial);
const QSGCurveFillNode *node = m->node();
- if (binding != 1 || node->gradientType() == QGradient::NoGradient)
+ if (binding != 1
+ || (node->gradientType() == QGradient::NoGradient && node->fillTextureProvider() == nullptr)) {
return;
+ }
+
+ QSGTexture *t = nullptr;
+ if (node->gradientType() != QGradient::NoGradient) {
+ const QSGGradientCacheKey cacheKey(node->fillGradient()->stops,
+ node->fillGradient()->spread);
+ t = QSGGradientCache::cacheForRhi(state.rhi())->get(cacheKey);
+ } else if (node->fillTextureProvider() != nullptr) {
+ t = node->fillTextureProvider()->texture();
+ if (t != nullptr && t->isAtlasTexture()) {
+ // Create a non-atlas copy to make texture coordinate wrapping work. This
+ // texture copy is owned by the QSGTexture so memory is managed with the original
+ // texture provider.
+ QSGTexture *newTexture = t->removedFromAtlas(state.resourceUpdateBatch());
+ if (newTexture != nullptr)
+ t = newTexture;
+ }
+
+ }
+
+ if (t != nullptr) {
+ t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+ } else {
+ if (m->dummyTexture() == nullptr) {
+ QSGPlainTexture *dummyTexture = new QSGPlainTexture;
+ dummyTexture->setFiltering(QSGTexture::Nearest);
+ dummyTexture->setHorizontalWrapMode(QSGTexture::Repeat);
+ dummyTexture->setVerticalWrapMode(QSGTexture::Repeat);
+ QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
+ img.fill(0);
+ dummyTexture->setImage(img);
+ dummyTexture->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+
+ m->setDummyTexture(dummyTexture);
+ }
+
+ t = m->dummyTexture();
+ }
- const QSGGradientCacheKey cacheKey(node->fillGradient().stops,
- node->fillGradient().spread);
- QSGTexture *t = QSGGradientCache::cacheForRhi(state.rhi())->get(cacheKey);
- t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
*texture = t;
}
@@ -81,11 +116,11 @@ namespace {
}
matrixScale = qSqrt(qAbs(state.determinant()));
- memcpy(buf->data() + offset + matrixCount * 64, &matrixScale, 4);
+ memcpy(buf->data() + offset + newEffect->viewCount() * 64, &matrixScale, 4);
changed = true;
}
- offset += matrixCount * 64 + 4;
+ offset += newEffect->viewCount() * 64 + 4;
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
@@ -110,36 +145,8 @@ namespace {
}
offset += 8;
- if (newNode->hasStroke()) {
- Q_ASSERT(buf->size() >= offset + 32);
- QVector4D newStrokeColor(newNode->strokeColor().redF(),
- newNode->strokeColor().greenF(),
- newNode->strokeColor().blueF(),
- newNode->strokeColor().alphaF());
- QVector4D oldStrokeColor = oldNode != nullptr
- ? QVector4D(oldNode->strokeColor().redF(),
- oldNode->strokeColor().greenF(),
- oldNode->strokeColor().blueF(),
- oldNode->strokeColor().alphaF())
- : QVector4D{};
-
- if (oldNode == nullptr || oldStrokeColor != newStrokeColor) {
- memcpy(buf->data() + offset, &newStrokeColor, 16);
- changed = true;
- }
- offset += 16;
-
- if (oldNode == nullptr
- || !qFuzzyCompare(newNode->strokeWidth(), oldNode->strokeWidth())
- || (state.isMatrixDirty() && newNode->strokeWidth() > 0.0f)) {
- float w = newNode->strokeWidth() * matrixScale; // matrixScale calculated earlier
- memcpy(buf->data() + offset, &w, 4);
- changed = true;
- }
- offset += 16;
- }
-
- if (newNode->gradientType() == QGradient::NoGradient) {
+ if (newNode->gradientType() == QGradient::NoGradient
+ && newNode->fillTextureProvider() == nullptr) {
Q_ASSERT(buf->size() >= offset + 16);
QVector4D newColor = QVector4D(newNode->color().redF(),
@@ -159,12 +166,42 @@ namespace {
}
offset += 16;
+ } else {
+ Q_ASSERT(buf->size() >= offset + 64);
+
+ if (!oldNode || *oldNode->fillTransform() != *newNode->fillTransform()) {
+ memcpy(buf->data() + offset, newNode->fillTransform()->invertedData(), 64);
+ changed = true;
+ }
+
+ offset += 64;
+ }
+
+ if (newNode->gradientType() == QGradient::NoGradient
+ && newNode->fillTextureProvider() != nullptr) {
+ Q_ASSERT(buf->size() >= offset + 8);
+ const QSizeF newTextureSize = newNode->fillTextureProvider()->texture() != nullptr
+ ? newNode->fillTextureProvider()->texture()->textureSize()
+ : QSizeF(0, 0);
+ const QVector2D newBoundsSize(newTextureSize.width() / state.devicePixelRatio(),
+ newTextureSize.height() / state.devicePixelRatio());
+ const QVector2D oldBoundsSize = oldNode != nullptr
+ ? oldNode->boundsSize()
+ : QVector2D{};
+
+ if (oldEffect == nullptr || newBoundsSize != oldBoundsSize) {
+ newNode->setBoundsSize(newBoundsSize);
+ memcpy(buf->data() + offset, &newBoundsSize, 8);
+ changed = true;
+ }
+ offset += 8;
+
} else if (newNode->gradientType() == QGradient::LinearGradient) {
Q_ASSERT(buf->size() >= offset + 8 + 8);
- QVector2D newGradientStart = QVector2D(newNode->fillGradient().a);
+ QVector2D newGradientStart = QVector2D(newNode->fillGradient()->a);
QVector2D oldGradientStart = oldNode != nullptr
- ? QVector2D(oldNode->fillGradient().a)
+ ? QVector2D(oldNode->fillGradient()->a)
: QVector2D{};
if (newGradientStart != oldGradientStart || oldEffect == nullptr) {
@@ -173,9 +210,9 @@ namespace {
}
offset += 8;
- QVector2D newGradientEnd = QVector2D(newNode->fillGradient().b);
+ QVector2D newGradientEnd = QVector2D(newNode->fillGradient()->b);
QVector2D oldGradientEnd = oldNode!= nullptr
- ? QVector2D(oldNode->fillGradient().b)
+ ? QVector2D(oldNode->fillGradient()->b)
: QVector2D{};
if (newGradientEnd != oldGradientEnd || oldEffect == nullptr) {
@@ -187,9 +224,9 @@ namespace {
} else if (newNode->gradientType() == QGradient::RadialGradient) {
Q_ASSERT(buf->size() >= offset + 8 + 8 + 4 + 4);
- QVector2D newFocalPoint = QVector2D(newNode->fillGradient().b);
+ QVector2D newFocalPoint = QVector2D(newNode->fillGradient()->b);
QVector2D oldFocalPoint = oldNode != nullptr
- ? QVector2D(oldNode->fillGradient().b)
+ ? QVector2D(oldNode->fillGradient()->b)
: QVector2D{};
if (oldNode == nullptr || newFocalPoint != oldFocalPoint) {
memcpy(buf->data() + offset, &newFocalPoint, 8);
@@ -197,9 +234,9 @@ namespace {
}
offset += 8;
- QVector2D newCenterPoint = QVector2D(newNode->fillGradient().a);
+ QVector2D newCenterPoint = QVector2D(newNode->fillGradient()->a);
QVector2D oldCenterPoint = oldNode != nullptr
- ? QVector2D(oldNode->fillGradient().a)
+ ? QVector2D(oldNode->fillGradient()->a)
: QVector2D{};
QVector2D newCenterToFocal = newCenterPoint - newFocalPoint;
@@ -210,9 +247,9 @@ namespace {
}
offset += 8;
- float newCenterRadius = newNode->fillGradient().v0;
+ float newCenterRadius = newNode->fillGradient()->v0;
float oldCenterRadius = oldNode != nullptr
- ? oldNode->fillGradient().v0
+ ? oldNode->fillGradient()->v0
: 0.0f;
if (oldNode == nullptr || !qFuzzyCompare(newCenterRadius, oldCenterRadius)) {
memcpy(buf->data() + offset, &newCenterRadius, 4);
@@ -220,9 +257,9 @@ namespace {
}
offset += 4;
- float newFocalRadius = newNode->fillGradient().v1;
+ float newFocalRadius = newNode->fillGradient()->v1;
float oldFocalRadius = oldNode != nullptr
- ? oldNode->fillGradient().v1
+ ? oldNode->fillGradient()->v1
: 0.0f;
if (oldNode == nullptr || !qFuzzyCompare(newFocalRadius, oldFocalRadius)) {
memcpy(buf->data() + offset, &newFocalRadius, 4);
@@ -233,9 +270,9 @@ namespace {
} else if (newNode->gradientType() == QGradient::ConicalGradient) {
Q_ASSERT(buf->size() >= offset + 8 + 4);
- QVector2D newFocalPoint = QVector2D(newNode->fillGradient().a);
+ QVector2D newFocalPoint = QVector2D(newNode->fillGradient()->a);
QVector2D oldFocalPoint = oldNode != nullptr
- ? QVector2D(oldNode->fillGradient().a)
+ ? QVector2D(oldNode->fillGradient()->a)
: QVector2D{};
if (oldNode == nullptr || newFocalPoint != oldFocalPoint) {
memcpy(buf->data() + offset, &newFocalPoint, 8);
@@ -243,9 +280,9 @@ namespace {
}
offset += 8;
- float newAngle = newNode->fillGradient().v0;
+ float newAngle = newNode->fillGradient()->v0;
float oldAngle = oldNode != nullptr
- ? oldNode->fillGradient().v0
+ ? oldNode->fillGradient()->v0
: 0.0f;
if (oldNode == nullptr || !qFuzzyCompare(newAngle, oldAngle)) {
newAngle = -qDegreesToRadians(newAngle);
@@ -257,6 +294,7 @@ namespace {
return changed;
}
+
}
QSGCurveFillMaterial::QSGCurveFillMaterial(QSGCurveFillNode *node)
@@ -266,6 +304,11 @@ QSGCurveFillMaterial::QSGCurveFillMaterial(QSGCurveFillNode *node)
setFlag(RequiresDeterminant, true);
}
+QSGCurveFillMaterial::~QSGCurveFillMaterial()
+{
+ delete m_dummyTexture;
+}
+
int QSGCurveFillMaterial::compare(const QSGMaterial *other) const
{
if (other->type() != type())
@@ -279,10 +322,7 @@ int QSGCurveFillMaterial::compare(const QSGMaterial *other) const
if (a == b)
return 0;
- if (int d = a->strokeColor().rgba() - b->strokeColor().rgba())
- return d;
-
- if (a->gradientType() == QGradient::NoGradient) {
+ if (a->gradientType() == QGradient::NoGradient && a->fillTextureProvider() == nullptr) {
if (int d = a->color().red() - b->color().red())
return d;
if (int d = a->color().green() - b->color().green())
@@ -292,48 +332,54 @@ int QSGCurveFillMaterial::compare(const QSGMaterial *other) const
if (int d = a->color().alpha() - b->color().alpha())
return d;
} else {
- const QSGGradientCache::GradientDesc &ga = a->fillGradient();
- const QSGGradientCache::GradientDesc &gb = b->fillGradient();
-
- if (int d = ga.a.x() - gb.a.x())
- return d;
- if (int d = ga.a.y() - gb.a.y())
- return d;
- if (int d = ga.b.x() - gb.b.x())
- return d;
- if (int d = ga.b.y() - gb.b.y())
- return d;
-
- if (int d = ga.v0 - gb.v0)
- return d;
- if (int d = ga.v1 - gb.v1)
- return d;
+ if (a->gradientType() != QGradient::NoGradient) {
+ const QSGGradientCache::GradientDesc &ga = *a->fillGradient();
+ const QSGGradientCache::GradientDesc &gb = *b->fillGradient();
- if (int d = ga.spread - gb.spread)
- return d;
+ if (int d = ga.a.x() - gb.a.x())
+ return d;
+ if (int d = ga.a.y() - gb.a.y())
+ return d;
+ if (int d = ga.b.x() - gb.b.x())
+ return d;
+ if (int d = ga.b.y() - gb.b.y())
+ return d;
- if (int d = ga.stops.size() - gb.stops.size())
- return d;
+ if (int d = ga.v0 - gb.v0)
+ return d;
+ if (int d = ga.v1 - gb.v1)
+ return d;
- for (int i = 0; i < ga.stops.size(); ++i) {
- if (int d = ga.stops[i].first - gb.stops[i].first)
+ if (int d = ga.spread - gb.spread)
return d;
- if (int d = ga.stops[i].second.rgba() - gb.stops[i].second.rgba())
+
+ if (int d = ga.stops.size() - gb.stops.size())
return d;
+
+ for (int i = 0; i < ga.stops.size(); ++i) {
+ if (int d = ga.stops[i].first - gb.stops[i].first)
+ return d;
+ if (int d = ga.stops[i].second.rgba() - gb.stops[i].second.rgba())
+ return d;
+ }
}
+
+ if (int d = a->fillTransform()->compareTo(*b->fillTransform()))
+ return d;
}
- return 0;
+ const qintptr diff = qintptr(a->fillTextureProvider()) - qintptr(b->fillTextureProvider());
+ return diff < 0 ? -1 : (diff > 0 ? 1 : 0);
}
QSGMaterialType *QSGCurveFillMaterial::type() const
{
- static QSGMaterialType type[8];
+ static QSGMaterialType type[5];
uint index = node()->gradientType();
Q_ASSERT((index & ~3) == 0); // Only two first bits for gradient type
- if (node()->hasStroke())
- index |= 4;
+ if (node()->gradientType() == QGradient::NoGradient && node()->fillTextureProvider() != nullptr)
+ index = 5;
return &type[index];
}
@@ -341,10 +387,10 @@ QSGMaterialType *QSGCurveFillMaterial::type() const
QSGMaterialShader *QSGCurveFillMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
{
return new QSGCurveFillMaterialShader(node()->gradientType(),
- node()->hasStroke(),
+ node()->gradientType() == QGradient::NoGradient
+ && node()->fillTextureProvider() != nullptr,
renderMode == QSGRendererInterface::RenderMode3D,
viewCount());
}
-
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgcurvefillnode_p.h b/src/quick/scenegraph/qsgcurvefillnode_p.h
index d96a78cde9..441576a814 100644
--- a/src/quick/scenegraph/qsgcurvefillnode_p.h
+++ b/src/quick/scenegraph/qsgcurvefillnode_p.h
@@ -8,7 +8,9 @@
#include <QtQuick/qtquickexports.h>
#include <QtQuick/private/qsggradientcache_p.h>
+#include <QtQuick/private/qsgtransform_p.h>
#include <QtQuick/qsgnode.h>
+#include <QtQuick/qsgtextureprovider.h>
#include "qsgcurveabstractnode_p.h"
@@ -25,17 +27,18 @@
QT_BEGIN_NAMESPACE
-class Q_QUICK_EXPORT QSGCurveFillNode : public QSGCurveAbstractNode
+class QSGTextureProvider;
+
+class Q_QUICK_EXPORT QSGCurveFillNode : public QObject, public QSGCurveAbstractNode
{
+ Q_OBJECT
public:
QSGCurveFillNode();
void setColor(QColor col) override
{
- if (m_color == col)
- return;
m_color = col;
- updateMaterial();
+ markDirty(DirtyMaterial);
}
QColor color() const
@@ -43,48 +46,50 @@ public:
return m_color;
}
- void setStrokeColor(QColor col)
+ void setFillTextureProvider(QSGTextureProvider *provider)
{
- const bool hadStroke = hasStroke();
- m_strokeColor = col;
- if (hadStroke != hasStroke())
- updateMaterial();
- }
+ if (provider == m_textureProvider)
+ return;
- QColor strokeColor() const
- {
- return m_strokeColor;
- }
+ if (m_textureProvider != nullptr) {
+ disconnect(m_textureProvider, &QSGTextureProvider::textureChanged,
+ this, &QSGCurveFillNode::handleTextureChanged);
+ disconnect(m_textureProvider, &QSGTextureProvider::destroyed,
+ this, &QSGCurveFillNode::handleTextureProviderDestroyed);
+ }
- void setStrokeWidth(float width)
- {
- const bool hadStroke = hasStroke();
- m_strokeWidth = width;
- if (hadStroke != hasStroke())
- updateMaterial();
+ m_textureProvider = provider;
+ markDirty(DirtyMaterial);
+
+ if (m_textureProvider != nullptr) {
+ connect(m_textureProvider, &QSGTextureProvider::textureChanged,
+ this, &QSGCurveFillNode::handleTextureChanged);
+ connect(m_textureProvider, &QSGTextureProvider::destroyed,
+ this, &QSGCurveFillNode::handleTextureProviderDestroyed);
+ }
}
- float strokeWidth() const
+
+ QSGTextureProvider *fillTextureProvider() const
{
- return m_strokeWidth;
+ return m_textureProvider;
}
void setFillGradient(const QSGGradientCache::GradientDesc &fillGradient)
{
m_fillGradient = fillGradient;
+ markDirty(DirtyMaterial);
}
- QSGGradientCache::GradientDesc fillGradient() const
+ const QSGGradientCache::GradientDesc *fillGradient() const
{
- return m_fillGradient;
+ return &m_fillGradient;
}
void setGradientType(QGradient::Type type)
{
- if (m_gradientType != type) {
- m_gradientType = type;
- updateMaterial();
- }
+ m_gradientType = type;
+ markDirty(DirtyMaterial);
}
QGradient::Type gradientType() const
@@ -92,20 +97,25 @@ public:
return m_gradientType;
}
- float debug() const
+ void setFillTransform(const QSGTransform &transform)
{
- return m_debug;
+ m_fillTransform = transform;
+ markDirty(DirtyMaterial);
}
- void setDebug(float newDebug)
+ const QSGTransform *fillTransform() const
{
- m_debug = newDebug;
+ return &m_fillTransform;
}
+ float debug() const
+ {
+ return m_debug;
+ }
- bool hasStroke() const
+ void setDebug(float newDebug)
{
- return m_strokeWidth > 0.0f && m_strokeColor.alpha() > 0;
+ m_debug = newDebug;
}
void appendTriangle(const std::array<QVector2D, 3> &v, // triangle vertices
@@ -203,6 +213,36 @@ public:
m_uncookedVertexes.reserve(size);
}
+ void preprocess() override
+ {
+ if (m_textureProvider != nullptr) {
+ if (QSGDynamicTexture *texture = qobject_cast<QSGDynamicTexture *>(m_textureProvider->texture()))
+ texture->updateTexture();
+ }
+ }
+
+ QVector2D boundsSize() const
+ {
+ return m_boundsSize;
+ }
+
+ void setBoundsSize(const QVector2D &boundsSize)
+ {
+ m_boundsSize = boundsSize;
+ }
+
+private Q_SLOTS:
+ void handleTextureChanged()
+ {
+ markDirty(DirtyMaterial);
+ }
+
+ void handleTextureProviderDestroyed()
+ {
+ m_textureProvider = nullptr;
+ markDirty(DirtyMaterial);
+ }
+
private:
struct CurveNodeVertex
{
@@ -214,17 +254,18 @@ private:
void updateMaterial();
static const QSGGeometry::AttributeSet &attributes();
- QColor m_color = Qt::white;
- QColor m_strokeColor = Qt::transparent;
- float m_strokeWidth = 0.0f;
- float m_debug = 0.0f;
- QSGGradientCache::GradientDesc m_fillGradient;
- QGradient::Type m_gradientType = QGradient::NoGradient;
-
QScopedPointer<QSGMaterial> m_material;
QVector<CurveNodeVertex> m_uncookedVertexes;
QVector<quint32> m_uncookedIndexes;
+
+ QSGGradientCache::GradientDesc m_fillGradient;
+ QSGTextureProvider *m_textureProvider = nullptr;
+ QVector2D m_boundsSize;
+ QSGTransform m_fillTransform;
+ QColor m_color = Qt::white;
+ QGradient::Type m_gradientType = QGradient::NoGradient;
+ float m_debug = 0.0f;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgcurvefillnode_p_p.h b/src/quick/scenegraph/qsgcurvefillnode_p_p.h
index f2a6535c6f..9cc80f3dca 100644
--- a/src/quick/scenegraph/qsgcurvefillnode_p_p.h
+++ b/src/quick/scenegraph/qsgcurvefillnode_p_p.h
@@ -21,10 +21,12 @@
QT_BEGIN_NAMESPACE
class QSGCurveFillNode;
+class QSGPlainTexture;
class Q_QUICK_EXPORT QSGCurveFillMaterial : public QSGMaterial
{
public:
QSGCurveFillMaterial(QSGCurveFillNode *node);
+ ~QSGCurveFillMaterial() override;
int compare(const QSGMaterial *other) const override;
QSGCurveFillNode *node() const
@@ -32,11 +34,22 @@ public:
return m_node;
}
+ QSGPlainTexture *dummyTexture() const
+ {
+ return m_dummyTexture;
+ }
+
+ void setDummyTexture(QSGPlainTexture *dummyTexture)
+ {
+ m_dummyTexture = dummyTexture;
+ }
+
private:
QSGMaterialType *type() const override;
QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override;
QSGCurveFillNode *m_node;
+ QSGPlainTexture *m_dummyTexture = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgcurveprocessor.cpp b/src/quick/scenegraph/qsgcurveprocessor.cpp
index f2e95d691c..771b2d7cf3 100644
--- a/src/quick/scenegraph/qsgcurveprocessor.cpp
+++ b/src/quick/scenegraph/qsgcurveprocessor.cpp
@@ -1379,7 +1379,7 @@ bool QSGCurveProcessor::solveIntersections(QQuadPath &path, bool removeNestedPat
// For winding fill we take the left most path forward, so the inside stays on the right side
// For odd even fill we take the right most path forward so we cut of the smallest area.
// We come back at the intersection and add the missing pieces as subpaths later on.
- if (t2 != 0 && t2 != 1) {
+ if (t1 !=0 && t1 != 1 && t2 != 0 && t2 != 1) {
QVector2D tangent1 = elem1.tangentAtFraction(t1);
if (!forward)
tangent1 = -tangent1;
diff --git a/src/quick/scenegraph/qsgrhisupport.cpp b/src/quick/scenegraph/qsgrhisupport.cpp
index a24a3e6160..45c183a5f8 100644
--- a/src/quick/scenegraph/qsgrhisupport.cpp
+++ b/src/quick/scenegraph/qsgrhisupport.cpp
@@ -1602,6 +1602,8 @@ QRhiTexture::Format QSGRhiSupport::toRhiTextureFormat(uint nativeFormat, QRhiTex
default:
return QRhiTexture::UnknownFormat;
}
+ Q_UNUSED(nativeFormat)
+ Q_UNUSED(flags)
}
bool QSGRhiSupport::attemptReinitWithSwRastUponFail() const
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 84450c692b..902d6991fb 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -18,6 +18,7 @@
#include <QtQuick/QQuickWindow>
#include <private/qquickwindow_p.h>
#include <private/qquickitem_p.h>
+#include <QtGui/qpa/qplatformwindow_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
@@ -1461,10 +1462,29 @@ void QSGThreadedRenderLoop::update(QQuickWindow *window)
if (!w)
return;
- if (w->thread == QThread::currentThread()) {
- qCDebug(QSG_LOG_RENDERLOOP) << "update on window - on render thread" << w->window;
- w->thread->requestRepaint();
- return;
+ const bool isRenderThread = QThread::currentThread() == w->thread;
+
+#if defined(Q_OS_MACOS)
+ using namespace QNativeInterface::Private;
+ if (auto *cocoaWindow = dynamic_cast<QCocoaWindow*>(window->handle())) {
+ // If the window is being resized we don't want to schedule unthrottled
+ // updates on the render thread, as this will starve the main thread
+ // from getting drawables for displaying the updated window size.
+ if (isRenderThread && cocoaWindow->inLiveResize()) {
+ // In most cases the window will already have update requested
+ // due to the animator triggering a sync, but just in case we
+ // schedule an update request on the main thread explicitly.
+ qCDebug(QSG_LOG_RENDERLOOP) << "window is resizing. update on window" << w->window;
+ QTimer::singleShot(0, window, [=]{ window->requestUpdate(); });
+ return;
+ }
+ }
+#endif
+
+ if (isRenderThread) {
+ qCDebug(QSG_LOG_RENDERLOOP) << "update on window - on render thread" << w->window;
+ w->thread->requestRepaint();
+ return;
}
qCDebug(QSG_LOG_RENDERLOOP) << "update on window" << w->window;
diff --git a/src/quick/scenegraph/shaders_ng/shapecurve.frag b/src/quick/scenegraph/shaders_ng/shapecurve.frag
index 594bed7c11..cc97f375ab 100644
--- a/src/quick/scenegraph/shaders_ng/shapecurve.frag
+++ b/src/quick/scenegraph/shaders_ng/shapecurve.frag
@@ -10,9 +10,10 @@ layout(location = 1) in vec4 gradient;
layout(location = 2) in float gradTabIndex;
#elif defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
layout(location = 2) in vec2 coord;
+#elif defined(TEXTUREFILL)
+layout(location = 2) in vec2 textureCoord;
#endif
-
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
@@ -26,14 +27,9 @@ layout(std140, binding = 0) uniform buf {
float debug;
float reserved3;
-#if defined(STROKE)
- vec4 strokeColor;
- float strokeWidth;
- float reserved4;
- float reserved5;
- float reserved6;
+#if defined(LINEARGRADIENT) || defined(RADIALGRADIENT) || defined(CONICALGRADIENT) || defined(TEXTUREFILL)
+ mat4 gradientMatrix;
#endif
-
#if defined(LINEARGRADIENT)
vec2 gradientStart;
vec2 gradientEnd;
@@ -45,6 +41,8 @@ layout(std140, binding = 0) uniform buf {
#elif defined(CONICALGRADIENT)
vec2 translationPoint;
float angle;
+#elif defined(TEXTUREFILL)
+ vec2 boundsSize;
#else
vec4 color;
#endif
@@ -54,6 +52,8 @@ layout(std140, binding = 0) uniform buf {
#if defined(LINEARGRADIENT) || defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
layout(binding = 1) uniform sampler2D gradTabTexture;
+#elif defined(TEXTUREFILL)
+layout(binding = 1) uniform sampler2D sourceTexture;
#endif
vec4 baseColor()
@@ -82,6 +82,8 @@ vec4 baseColor()
else
t = (atan(-coord.y, coord.x) + ubuf.angle) * INVERSE_2PI;
return texture(gradTabTexture, vec2(t - floor(t), 0.5));
+#elif defined(TEXTUREFILL)
+ return texture(sourceTexture, textureCoord);
#else
return vec4(ubuf.color.rgb, 1.0) * ubuf.color.a;
#endif
@@ -142,27 +144,9 @@ void main()
float debugB = isCurve * min(1.0, 1.0 - qt_TexCoord.z * -1.0) + debugG;
vec3 debugColor = vec3(debugR, debugG, debugB);
-#if defined(STROKE)
- float distance = (f / df); // distance from centre of fragment to line
-
- float halfStrokeWidth = ubuf.strokeWidth / 2.0;
-
- // calculate stroke
- float strokeCoverage = 1.0 - clamp(0.5 + abs(distance) - halfStrokeWidth, 0.0, 1.0);
- vec4 stroke = ubuf.strokeColor * strokeCoverage;
-
- float fillCoverage = clamp(0.5 + f / df, 0.0, 1.0);
- vec4 fill = baseColor() * fillCoverage;
-
- vec4 combined = fill * (1.0 - stroke.a) + stroke * stroke.a;
-
- // finally mix in debug
- fragColor = mix(combined, vec4(debugColor, 1.0), ubuf.debug) * ubuf.opacity;
-#else
// Special case: mask out concave curve in "negative space".
int specialCaseMask = 1 - int(qt_TexCoord.w != 0.0) * (int(qt_TexCoord.x < 0.0) + int(qt_TexCoord.x > 1.0));
float fillCoverage = clamp(0.5 + f / df, 0.0, 1.0) * float(specialCaseMask);
fragColor = mix(baseColor() * fillCoverage, vec4(debugColor, 1.0), ubuf.debug) * ubuf.opacity;
-#endif
}
diff --git a/src/quick/scenegraph/shaders_ng/shapecurve.vert b/src/quick/scenegraph/shaders_ng/shapecurve.vert
index 59f4ddb77d..3ff53978b8 100644
--- a/src/quick/scenegraph/shaders_ng/shapecurve.vert
+++ b/src/quick/scenegraph/shaders_ng/shapecurve.vert
@@ -12,6 +12,8 @@ layout(location = 1) out vec4 gradient;
layout(location = 2) out float gradTabIndex;
#elif defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
layout(location = 2) out vec2 coord;
+#elif defined(TEXTUREFILL)
+layout(location = 2) out vec2 textureCoord;
#endif
layout(std140, binding = 0) uniform buf {
@@ -25,14 +27,9 @@ layout(std140, binding = 0) uniform buf {
float debug;
float reserved3;
-#if defined(STROKE)
- vec4 strokeColor;
- float strokeWidth;
- float reserved4;
- float reserved5;
- float reserved6;
+#if defined(LINEARGRADIENT) || defined(RADIALGRADIENT) || defined(CONICALGRADIENT) || defined(TEXTUREFILL)
+ mat4 gradientMatrix;
#endif
-
#if defined(LINEARGRADIENT)
vec2 gradientStart;
vec2 gradientEnd;
@@ -44,6 +41,8 @@ layout(std140, binding = 0) uniform buf {
#elif defined(CONICALGRADIENT)
vec2 translationPoint;
float angle;
+#elif defined(TEXTUREFILL)
+ vec2 boundsSize;
#else
vec4 color;
#endif
@@ -72,11 +71,17 @@ void main()
gradient = vertexGradient / ubuf.matrixScale;
+#if defined(LINEARGRADIENT) || defined(RADIALGRADIENT) || defined(CONICALGRADIENT) || defined(TEXTUREFILL)
+ vec2 gradVertexCoord = (ubuf.gradientMatrix * vertexCoord).xy;
+#endif
#if defined(LINEARGRADIENT)
vec2 gradVec = ubuf.gradientEnd - ubuf.gradientStart;
- gradTabIndex = dot(gradVec, vertexCoord.xy - ubuf.gradientStart.xy) / dot(gradVec, gradVec);
+ gradTabIndex = dot(gradVec, gradVertexCoord - ubuf.gradientStart) / dot(gradVec, gradVec);
#elif defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
- coord = vertexCoord.xy - ubuf.translationPoint;
+ coord = gradVertexCoord - ubuf.translationPoint;
+#elif defined(TEXTUREFILL)
+ textureCoord = vec2(gradVertexCoord.x / ubuf.boundsSize.x,
+ gradVertexCoord.y / ubuf.boundsSize.y);
#endif
#if QSHADER_VIEW_COUNT >= 2
diff --git a/src/quick/scenegraph/util/qsgtransform.cpp b/src/quick/scenegraph/util/qsgtransform.cpp
new file mode 100644
index 0000000000..7efb014c33
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgtransform.cpp
@@ -0,0 +1,10 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qsgtransform_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QMatrix4x4 QSGTransform::m_identity;
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgtransform_p.h b/src/quick/scenegraph/util/qsgtransform_p.h
new file mode 100644
index 0000000000..f19d7a0efd
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgtransform_p.h
@@ -0,0 +1,105 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSGTRANSFORM_P_H
+#define QSGTRANSFORM_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QSharedPointer>
+#include <QMatrix4x4>
+#include <QtQuick/qtquickexports.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_EXPORT QSGTransform
+{
+public:
+ void setMatrix(const QMatrix4x4 &matrix)
+ {
+ if (matrix.isIdentity())
+ m_matrixPtr.clear();
+ else
+ m_matrixPtr = QSharedPointer<QMatrix4x4>::create(matrix);
+ m_invertedPtr.clear();
+ }
+
+ QMatrix4x4 matrix() const
+ {
+ return m_matrixPtr ? *m_matrixPtr : m_identity;
+ }
+
+ bool isIdentity() const
+ {
+ return !m_matrixPtr;
+ }
+
+ bool operator==(const QMatrix4x4 &other) const
+ {
+ return m_matrixPtr ? (other == *m_matrixPtr) : other.isIdentity();
+ }
+
+ bool operator!=(const QMatrix4x4 &other) const
+ {
+ return !(*this == other);
+ }
+
+ bool operator==(const QSGTransform &other) const
+ {
+ return (m_matrixPtr == other.m_matrixPtr)
+ || (m_matrixPtr && other.m_matrixPtr && *m_matrixPtr == *other.m_matrixPtr);
+ }
+
+ bool operator!=(const QSGTransform &other) const
+ {
+ return !(*this == other);
+ }
+
+ int compareTo(const QSGTransform &other) const
+ {
+ int diff = 0;
+ if (m_matrixPtr != other.m_matrixPtr) {
+ if (m_matrixPtr.isNull()) {
+ diff = -1;
+ } else if (other.m_matrixPtr.isNull()) {
+ diff = 1;
+ } else {
+ const float *ptr1 = m_matrixPtr->constData();
+ const float *ptr2 = other.m_matrixPtr->constData();
+ for (int i = 0; i < 16 && !diff; i++) {
+ float d = ptr1[i] - ptr2[i];
+ if (d != 0)
+ diff = (d > 0) ? 1 : -1;
+ }
+ }
+ }
+ return diff;
+ }
+
+ const float *invertedData() const
+ {
+ if (!m_matrixPtr)
+ return m_identity.constData();
+ if (!m_invertedPtr)
+ m_invertedPtr = QSharedPointer<QMatrix4x4>::create(m_matrixPtr->inverted());
+ return m_invertedPtr->constData();
+ }
+
+private:
+ static QMatrix4x4 m_identity;
+ QSharedPointer<QMatrix4x4> m_matrixPtr;
+ mutable QSharedPointer<QMatrix4x4> m_invertedPtr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGTRANSFORM_P_H
diff --git a/src/quick/util/qminimalflatset_p.h b/src/quick/util/qminimalflatset_p.h
deleted file mode 100644
index 0a882205ef..0000000000
--- a/src/quick/util/qminimalflatset_p.h
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QTDECLARATIVE_QMINIMALFLATSET_P_H
-#define QTDECLARATIVE_QMINIMALFLATSET_P_H
-
-#if __has_include(<QtCore/private/qminimalflatset_p.h>)
-# include <QtCore/private/qminimalflatset_p.h>
-#else
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtQuick/qtquickglobal.h>
-
-#include <QtCore/qcontainerfwd.h>
-#include <QtCore/private/qglobal_p.h>
-
-//#define QMINIMAL_FLAT_SET_DEBUG
-#ifdef QMINIMAL_FLAT_SET_DEBUG
-# include <QtCore/qscopeguard.h>
-# include <QtCore/qdebug.h>
-# define QMINIMAL_FLAT_SET_PRINT_AT_END \
- const auto sg = qScopeGuard([&] { qDebug() << this << *this; });
-#else
-# define QMINIMAL_FLAT_SET_PRINT_AT_END
-#endif
-
-#include <algorithm> // for std::lower_bound
-
-QT_BEGIN_NAMESPACE
-
-/*
- This is a minimal version of a QFlatSet, the std::set version of QFlatMap.
- Like QFlatMap, it has linear insertion and removal, not logarithmic, like
- real QMap and std::set, so it's only a good container if you either have
- very few entries or lots, but with separate setup and lookup stages.
- Because a full QFlatSet would be 10x the work on writing this minimal one,
- we keep it here for now. When more users pop up and the class has matured a
- bit, we can consider moving it alongside QFlatMap in QtCore.
-*/
-
-template <typename T, typename Container = QList<T>>
-class QMinimalFlatSet
-{
- Container c;
-public:
- // compiler-generated default ctor is ok!
- // compiler-generated copy/move ctor/assignment operators are ok!
- // compiler-generated dtor is ok!
-
- using const_iterator = typename Container::const_iterator;
- using iterator = const_iterator;
- using const_reverse_iterator = typename Container::const_reverse_iterator;
- using reverse_iterator = const_reverse_iterator;
- using value_type = T;
-
- iterator begin() const { return c.cbegin(); }
- iterator end() const { return c.cend(); }
- iterator cbegin() const { return begin(); }
- iterator cend() const { return cend(); }
-
- reverse_iterator rbegin() const { return c.crbegin(); }
- reverse_iterator rend() const { return c.crend(); }
- reverse_iterator crbegin() const { return rbegin(); }
- reverse_iterator crend() const { return rend(); }
-
- void clear() {
- QMINIMAL_FLAT_SET_PRINT_AT_END
- c.clear();
- }
- auto size() const { return c.size(); }
- auto count() const { return size(); }
- bool isEmpty() const { return size() == 0; }
-
- std::pair<iterator, bool> insert(value_type &&v)
- {
- QMINIMAL_FLAT_SET_PRINT_AT_END
- const auto r = lookup(v);
- if (r.exists)
- return {r.it, false};
- else
- return {c.insert(r.it, std::move(v)), true};
- }
-
- std::pair<iterator, bool> insert(const value_type &v)
- {
- QMINIMAL_FLAT_SET_PRINT_AT_END
- const auto r = lookup(v);
- if (r.exists)
- return {r.it, false};
- else
- return {c.insert(r.it, v), true};
- }
-
- void erase(const value_type &v)
- {
- QMINIMAL_FLAT_SET_PRINT_AT_END
- const auto r = lookup(v);
- if (r.exists)
- c.erase(r.it);
- }
- void remove(const value_type &v) { erase(v); }
-
- bool contains(const value_type &v) const
- {
- return lookup(v).exists;
- }
-
- const Container &values() const & { return c; }
- Container values() && { return std::move(c); }
-
-private:
- auto lookup(const value_type &v) const
- {
- struct R {
- iterator it;
- bool exists;
- };
-
- const auto it = std::lower_bound(c.cbegin(), c.cend(), v);
- return R{it, it != c.cend() && !(v < *it)};
- }
-
-#ifdef QMINIMAL_FLAT_SET_DEBUG
- friend QDebug operator<<(QDebug dbg, const QMinimalFlatSet &set)
- {
- const QDebugStateSaver saver(dbg);
- dbg.nospace() << "QMinimalFlatSet{";
- for (auto &e : set)
- dbg << e << ", ";
- return dbg << "}";
- }
-#endif
-};
-
-QT_END_NAMESPACE
-
-#endif // !__has_include(<QtCore/private/qminimalflatset_p.h>)
-
-#endif // QTDECLARATIVE_QMINIMALFLATSET_P_H
diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp
index 34032d4801..ed2112fa0d 100644
--- a/src/quick/util/qquickdeliveryagent.cpp
+++ b/src/quick/util/qquickdeliveryagent.cpp
@@ -428,7 +428,7 @@ void QQuickDeliveryAgentPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *
}
}
- if (newActiveFocusItem && rootItem->hasFocus()) {
+ if (newActiveFocusItem && (rootItem->hasFocus() || (rootItem->window()->type() == Qt::Popup))) {
activeFocusItem = newActiveFocusItem;
QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true;
diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp
index 29c09abee2..c33111039f 100644
--- a/src/quick/util/qquickpath.cpp
+++ b/src/quick/util/qquickpath.cpp
@@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE
be instantiated.
\sa Path, PathAttribute, PathPercent, PathLine, PathPolyline, PathQuad, PathCubic, PathArc,
- PathAngleArc, PathCurve, PathSvg
+ PathAngleArc, PathCurve, PathSvg, PathRectangle
*/
/*!
@@ -70,7 +70,7 @@ QT_BEGIN_NAMESPACE
\li Yes
\li Yes
\row
- \li PathMultiLine
+ \li PathMultiline
\li Yes
\li Yes
\li Yes
@@ -100,6 +100,11 @@ QT_BEGIN_NAMESPACE
\li Yes
\li Yes
\row
+ \li PathRectangle
+ \li Yes
+ \li Yes
+ \li Yes
+ \row
\li PathAttribute
\li Yes
\li N/A
@@ -119,7 +124,7 @@ QT_BEGIN_NAMESPACE
\note Path is a non-visual type; it does not display anything on its own.
To draw a path, use \l Shape.
- \sa PathView, Shape, PathAttribute, PathPercent, PathLine, PathPolyline, PathMove, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg
+ \sa PathView, Shape, PathAttribute, PathPercent, PathLine, PathPolyline, PathMove, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg, PathRectangle
*/
QQuickPath::QQuickPath(QObject *parent)
: QObject(*(new QQuickPathPrivate), parent)
@@ -210,6 +215,7 @@ bool QQuickPath::isClosed() const
\li \l PathArc - an arc to a given position with a radius.
\li \l PathAngleArc - an arc specified by center point, radii, and angles.
\li \l PathSvg - a path specified as an SVG path data string.
+ \li \l PathRectangle - a rectangle with a given position and size
\li \l PathCurve - a point on a Catmull-Rom curve.
\li \l PathAttribute - an attribute at a given position in the path.
\li \l PathPercent - a way to spread out items along various segments of the path.
@@ -1191,7 +1197,7 @@ void QQuickPathAttribute::setValue(qreal value)
}
\endqml
- \sa Path, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg, PathMove, PathPolyline
+ \sa Path, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg, PathMove, PathPolyline, PathRectangle
*/
/*!
@@ -1467,7 +1473,7 @@ void QQuickPathQuad::addToPath(QPainterPath &path, const QQuickPathData &data)
\endqml
\endtable
- \sa Path, PathQuad, PathLine, PathArc, PathAngleArc, PathCurve, PathSvg
+ \sa Path, PathQuad, PathLine, PathArc, PathAngleArc, PathCurve, PathSvg, PathRectangle
*/
/*!
@@ -2035,7 +2041,7 @@ void QQuickPathArc::addToPath(QPainterPath &path, const QQuickPathData &data)
to work as part of a larger path (specifying start and end), PathAngleArc is designed
to make a path where the arc is primary (such as a circular progress indicator) more intuitive.
- \sa Path, PathLine, PathQuad, PathCubic, PathCurve, PathSvg, PathArc
+ \sa Path, PathLine, PathQuad, PathCubic, PathCurve, PathSvg, PathArc, PathRectangle
*/
/*!
@@ -2252,6 +2258,268 @@ void QQuickPathSvg::addToPath(QPainterPath &path, const QQuickPathData &)
/****************************************************************************/
/*!
+ \qmltype PathRectangle
+ \instantiates QQuickPathRectangle
+ \inqmlmodule QtQuick
+ \ingroup qtquick-animation-paths
+ \brief Defines a rectangle with optionally rounded corners.
+ \since QtQuick 6.8
+
+ PathRectangle provides an easy way to specify a rectangle, optionally with rounded corners. The
+ API corresponds to that of the \l Rectangle item.
+
+ \sa Path, PathLine, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg
+*/
+
+/*!
+ \qmlproperty real QtQuick::PathRectangle::x
+ \qmlproperty real QtQuick::PathRectangle::y
+
+ Defines the top left corner of the rectangle.
+
+ Unless that corner is rounded, this will also be the start and end point of the path.
+
+ \sa relativeX, relativeY
+*/
+
+/*!
+ \qmlproperty real QtQuick::PathRectangle::relativeX
+ \qmlproperty real QtQuick::PathRectangle::relativeY
+
+ Defines the top left corner of the rectangle relative to the path's start point.
+
+ If both a relative and absolute end position are specified for a single axis, the relative
+ position will be used.
+
+ Relative and absolute positions can be mixed, for example it is valid to set a relative x
+ and an absolute y.
+
+ \sa x, y
+*/
+
+/*!
+ \qmlproperty real QtQuick::PathRectangle::width
+ \qmlproperty real QtQuick::PathRectangle::height
+
+ Defines the width and height of the rectangle.
+
+ \sa x, y
+*/
+
+qreal QQuickPathRectangle::width() const
+{
+ return _width;
+}
+
+void QQuickPathRectangle::setWidth(qreal width)
+{
+ if (_width == width)
+ return;
+
+ _width = width;
+ emit widthChanged();
+ emit changed();
+}
+
+qreal QQuickPathRectangle::height() const
+{
+ return _height;
+}
+
+void QQuickPathRectangle::setHeight(qreal height)
+{
+ if (_height == height)
+ return;
+
+ _height = height;
+ emit heightChanged();
+ emit changed();
+}
+
+/*!
+ \qmlproperty real QtQuick::PathRectangle::strokeAdjustment
+
+ This property defines the stroke width adjustment to the rectangle coordinates.
+
+ When used in a \l ShapePath with stroking enabled, the actual stroked rectangle will by default
+ extend beyond the defined rectangle by half the stroke width on all sides. This is the expected
+ behavior since the path defines the midpoint line of the stroking, and corresponds to QPainter
+ and SVG rendering.
+
+ If one instead wants the defined rectangle to be the outer edge of the stroked rectangle, like
+ a \l Rectangle item with a border, one can set strokeAdjustment to the stroke width. This will
+ effectively shift all edges inwards by half the stroke width. Like in the following example:
+
+ \qml
+ ShapePath {
+ id: myRec
+ fillColor: "white"
+ strokeColor: "black"
+ strokeWidth: 16
+ joinStyle: ShapePath.MiterJoin
+
+ PathRectangle { x: 10; y: 10; width: 200; height: 100; strokeAdjustment: myRec.strokeWidth }
+ }
+ \endqml
+*/
+
+qreal QQuickPathRectangle::strokeAdjustment() const
+{
+ return _strokeAdjustment;
+}
+
+void QQuickPathRectangle::setStrokeAdjustment(qreal newStrokeAdjustment)
+{
+ if (_strokeAdjustment == newStrokeAdjustment)
+ return;
+ _strokeAdjustment = newStrokeAdjustment;
+ emit strokeAdjustmentChanged();
+ emit changed();
+}
+
+/*!
+ \qmlproperty real QtQuick::PathRectangle::radius
+
+ This property defines the corner radius used to define a rounded rectangle.
+
+ If radius is a positive value, the rectangle path will be defined as a rounded rectangle,
+ otherwise it will be defined as a normal rectangle.
+
+ This property may be overridden by the individual corner radius properties.
+
+ \sa topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius
+*/
+
+qreal QQuickPathRectangle::radius() const
+{
+ return _extra.isAllocated() ? _extra->radius : 0;
+}
+
+void QQuickPathRectangle::setRadius(qreal newRadius)
+{
+ if (_extra.value().radius == newRadius)
+ return;
+ _extra->radius = newRadius;
+ emit radiusChanged();
+ if (_extra->cornerRadii[Qt::TopLeftCorner] < 0)
+ emit topLeftRadiusChanged();
+ if (_extra->cornerRadii[Qt::TopRightCorner] < 0)
+ emit topRightRadiusChanged();
+ if (_extra->cornerRadii[Qt::BottomLeftCorner] < 0)
+ emit bottomLeftRadiusChanged();
+ if (_extra->cornerRadii[Qt::BottomRightCorner] < 0)
+ emit bottomRightRadiusChanged();
+ emit changed();
+}
+
+/*!
+ \qmlproperty real QtQuick::PathRectangle::topLeftRadius
+ \qmlproperty real QtQuick::PathRectangle::topRightRadius
+ \qmlproperty real QtQuick::PathRectangle::bottomLeftRadius
+ \qmlproperty real QtQuick::PathRectangle::bottomRightRadius
+
+ If set, these properties define the individual corner radii. A zero value defines that corner
+ to be sharp, while a positive value defines it to be rounded. When unset, the value of \l
+ radius is used instead.
+
+ These properties are unset by default. Assign \c undefined to them to return them to the unset
+ state.
+
+ \sa radius
+*/
+
+qreal QQuickPathRectangle::cornerRadius(Qt::Corner corner) const
+{
+ if (_extra.isAllocated())
+ return _extra->cornerRadii[corner] < 0 ? _extra->radius : _extra->cornerRadii[corner];
+ else
+ return 0;
+}
+
+void QQuickPathRectangle::setCornerRadius(Qt::Corner corner, qreal newCornerRadius)
+{
+ if (newCornerRadius < 0 || _extra.value().cornerRadii[corner] == newCornerRadius)
+ return;
+ _extra->cornerRadii[corner] = newCornerRadius;
+ emitCornerRadiusChanged(corner);
+}
+
+void QQuickPathRectangle::resetCornerRadius(Qt::Corner corner)
+{
+ if (!_extra.isAllocated() || _extra->cornerRadii[corner] < 0)
+ return;
+ _extra->cornerRadii[corner] = -1;
+ emitCornerRadiusChanged(corner);
+}
+
+void QQuickPathRectangle::emitCornerRadiusChanged(Qt::Corner corner)
+{
+ switch (corner) {
+ case Qt::TopLeftCorner:
+ emit topLeftRadiusChanged();
+ break;
+ case Qt::TopRightCorner:
+ emit topRightRadiusChanged();
+ break;
+ case Qt::BottomLeftCorner:
+ emit bottomLeftRadiusChanged();
+ break;
+ case Qt::BottomRightCorner:
+ emit bottomRightRadiusChanged();
+ break;
+ }
+ emit changed();
+}
+
+void QQuickPathRectangle::addToPath(QPainterPath &path, const QQuickPathData &data)
+{
+ QRectF rect(positionForCurve(data, path.currentPosition()), QSizeF(_width, _height));
+
+ qreal halfStroke = _strokeAdjustment * 0.5;
+ rect.adjust(halfStroke, halfStroke, -halfStroke, -halfStroke);
+ if (rect.isEmpty())
+ return;
+
+ if (!_extra.isAllocated()) {
+ // No rounded corners
+ path.addRect(rect);
+ } else {
+ // Radii must not exceed half of the width or half of the height
+ const qreal maxDiameter = qMin(rect.width(), rect.height());
+ const qreal generalDiameter = qMax(qreal(0), qMin(maxDiameter, 2 * _extra->radius));
+ auto effectiveDiameter = [&](Qt::Corner corner) {
+ qreal radius = _extra->cornerRadii[corner];
+ return radius < 0 ? generalDiameter : qMin(maxDiameter, 2 * radius);
+ };
+ const qreal diamTL = effectiveDiameter(Qt::TopLeftCorner);
+ const qreal diamTR = effectiveDiameter(Qt::TopRightCorner);
+ const qreal diamBL = effectiveDiameter(Qt::BottomLeftCorner);
+ const qreal diamBR = effectiveDiameter(Qt::BottomRightCorner);
+
+ path.moveTo(rect.left() + diamTL * 0.5, rect.top());
+ if (diamTR)
+ path.arcTo(QRectF(QPointF(rect.right() - diamTR, rect.top()), QSizeF(diamTR, diamTR)), 90, -90);
+ else
+ path.lineTo(rect.topRight());
+ if (diamBR)
+ path.arcTo(QRectF(QPointF(rect.right() - diamBR, rect.bottom() - diamBR), QSizeF(diamBR, diamBR)), 0, -90);
+ else
+ path.lineTo(rect.bottomRight());
+ if (diamBL)
+ path.arcTo(QRectF(QPointF(rect.left(), rect.bottom() - diamBL), QSizeF(diamBL, diamBL)), 270, -90);
+ else
+ path.lineTo(rect.bottomLeft());
+ if (diamTL)
+ path.arcTo(QRectF(rect.topLeft(), QSizeF(diamTL, diamTL)), 180, -90);
+ else
+ path.lineTo(rect.topLeft());
+ path.closeSubpath();
+ }
+}
+
+/****************************************************************************/
+
+/*!
\qmltype PathPercent
\instantiates QQuickPathPercent
\inqmlmodule QtQuick
@@ -2809,6 +3077,20 @@ void QQuickPathMultiline::addToPath(QPainterPath &path, const QQuickPathData &)
\include qquicktext.cpp qml-font-features
*/
+
+/*!
+ \qmlproperty bool QtQuick::PathText::font.contextFontMerging
+ \since 6.8
+
+ \include qquicktext.cpp qml-font-context-font-merging
+*/
+
+/*!
+ \qmlproperty bool QtQuick::PathText::font.preferTypoLineMetrics
+ \since 6.8
+
+ \include qquicktext.cpp qml-font-prefer-typo-line-metrics
+*/
void QQuickPathText::updatePath() const
{
if (!_path.isEmpty())
diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h
index 55400d2ddd..173bdd2fea 100644
--- a/src/quick/util/qquickpath_p.h
+++ b/src/quick/util/qquickpath_p.h
@@ -22,6 +22,7 @@ QT_REQUIRE_CONFIG(quick_path);
#include <qqml.h>
#include <private/qqmlnullablevalue_p.h>
+#include <private/qlazilyallocated_p.h>
#include <private/qbezier_p.h>
#include <private/qtquickglobal_p.h>
@@ -397,6 +398,83 @@ private:
QString _path;
};
+class Q_QUICK_EXPORT QQuickPathRectangle : public QQuickCurve
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged FINAL)
+ Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged FINAL)
+ Q_PROPERTY(qreal strokeAdjustment READ strokeAdjustment WRITE setStrokeAdjustment NOTIFY strokeAdjustmentChanged FINAL)
+ Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged FINAL)
+ Q_PROPERTY(qreal topLeftRadius READ topLeftRadius WRITE setTopLeftRadius RESET resetTopLeftRadius NOTIFY topLeftRadiusChanged FINAL)
+ Q_PROPERTY(qreal topRightRadius READ topRightRadius WRITE setTopRightRadius NOTIFY topRightRadiusChanged RESET resetTopRightRadius FINAL)
+ Q_PROPERTY(qreal bottomLeftRadius READ bottomLeftRadius WRITE setBottomLeftRadius NOTIFY bottomLeftRadiusChanged RESET resetBottomLeftRadius FINAL)
+ Q_PROPERTY(qreal bottomRightRadius READ bottomRightRadius WRITE setBottomRightRadius NOTIFY bottomRightRadiusChanged RESET resetBottomRightRadius FINAL)
+
+ QML_NAMED_ELEMENT(PathRectangle)
+ QML_ADDED_IN_VERSION(6, 8)
+public:
+ QQuickPathRectangle(QObject *parent = nullptr) : QQuickCurve(parent) {}
+
+ qreal width() const;
+ void setWidth(qreal width);
+
+ qreal height() const;
+ void setHeight(qreal height);
+
+ qreal strokeAdjustment() const;
+ void setStrokeAdjustment(qreal newStrokeAdjustment);
+
+ qreal radius() const;
+ void setRadius(qreal newRadius);
+
+ qreal topLeftRadius() const { return cornerRadius(Qt::TopLeftCorner); }
+ void setTopLeftRadius(qreal radius) { setCornerRadius(Qt::TopLeftCorner, radius); }
+ void resetTopLeftRadius() { resetCornerRadius(Qt::TopLeftCorner); }
+
+ qreal topRightRadius() const { return cornerRadius(Qt::TopRightCorner); }
+ void setTopRightRadius(qreal radius) { setCornerRadius(Qt::TopRightCorner, radius); }
+ void resetTopRightRadius() { resetCornerRadius(Qt::TopRightCorner); }
+
+ qreal bottomLeftRadius() const { return cornerRadius(Qt::BottomLeftCorner); }
+ void setBottomLeftRadius(qreal radius) { setCornerRadius(Qt::BottomLeftCorner, radius); }
+ void resetBottomLeftRadius() { resetCornerRadius(Qt::BottomLeftCorner); }
+
+ qreal bottomRightRadius() const { return cornerRadius(Qt::BottomRightCorner); }
+ void setBottomRightRadius(qreal radius) { setCornerRadius(Qt::BottomRightCorner, radius); }
+ void resetBottomRightRadius() { resetCornerRadius(Qt::BottomRightCorner); }
+
+ qreal cornerRadius(Qt::Corner corner) const;
+ void setCornerRadius(Qt::Corner corner, qreal newCornerRadius);
+ void resetCornerRadius(Qt::Corner corner);
+
+ void addToPath(QPainterPath &path, const QQuickPathData &) override;
+
+Q_SIGNALS:
+ void widthChanged();
+ void heightChanged();
+ void strokeAdjustmentChanged();
+ void radiusChanged();
+ void topLeftRadiusChanged();
+ void topRightRadiusChanged();
+ void bottomLeftRadiusChanged();
+ void bottomRightRadiusChanged();
+
+private:
+ void emitCornerRadiusChanged(Qt::Corner corner);
+
+ qreal _width = 0;
+ qreal _height = 0;
+ qreal _strokeAdjustment = 0;
+ struct ExtraData
+ {
+ ExtraData() { std::fill_n(cornerRadii, 4, -1); }
+ qreal radius = 0;
+ qreal cornerRadii[4];
+ };
+ QLazilyAllocated<ExtraData> _extra;
+};
+
class Q_QUICK_EXPORT QQuickPathPercent : public QQuickPathElement
{
Q_OBJECT
diff --git a/src/quick/util/qquickpixmap_p.h b/src/quick/util/qquickpixmap_p.h
index ad4fdb9111..f352da8d16 100644
--- a/src/quick/util/qquickpixmap_p.h
+++ b/src/quick/util/qquickpixmap_p.h
@@ -166,6 +166,7 @@ public:
static void purgeCache();
static bool isCached(const QUrl &url, const QRect &requestRegion, const QSize &requestSize,
const int frame, const QQuickImageProviderOptions &options);
+ static bool isScalableImageFormat(const QUrl &url);
static const QLatin1String itemGrabberScheme;
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 8de79f2009..10cc407c21 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -56,6 +56,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
Q_DECLARE_LOGGING_CATEGORY(lcQsgLeak)
#if defined(QT_DEBUG) && QT_CONFIG(thread)
@@ -2008,6 +2010,17 @@ bool QQuickPixmap::isCached(const QUrl &url, const QRect &requestRegion, const Q
return store->m_cache.contains(key);
}
+bool QQuickPixmap::isScalableImageFormat(const QUrl &url)
+{
+ if (url.scheme() == "image"_L1)
+ return true;
+
+ const QString stringUrl = url.path(QUrl::PrettyDecoded);
+ return stringUrl.endsWith("svg"_L1)
+ || stringUrl.endsWith("svgz"_L1)
+ || stringUrl.endsWith("pdf"_L1);
+}
+
bool QQuickPixmap::connectFinished(QObject *object, const char *method)
{
if (!d || !d->reply) {
diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp
index 527b8dbffe..a595dbcbc2 100644
--- a/src/quick/util/qquickstyledtext.cpp
+++ b/src/quick/util/qquickstyledtext.cpp
@@ -677,12 +677,11 @@ void QQuickStyledTextPrivate::parseImageAttributes(const QChar *&ch, const QStri
// to avoid a relayout later on.
QUrl url = baseUrl.resolved(image->url);
if (url.isLocalFile()) {
- image->pix = new QQuickPixmap(context->engine(), url, QRect(), image->size);
+ image->pix.reset(new QQuickPixmap(context->engine(), url, QRect(), image->size));
if (image->pix && image->pix->isReady()) {
image->size = image->pix->implicitSize();
} else {
- delete image->pix;
- image->pix = nullptr;
+ image->pix.reset();
}
}
}
diff --git a/src/quick/util/qquickstyledtext_p.h b/src/quick/util/qquickstyledtext_p.h
index af4b980c44..9f8ccf31e4 100644
--- a/src/quick/util/qquickstyledtext_p.h
+++ b/src/quick/util/qquickstyledtext_p.h
@@ -19,6 +19,7 @@
#include <QPointF>
#include <QList>
#include <QUrl>
+#include <QScopedPointer>
#include <QtQuick/private/qquickpixmap_p.h>
QT_BEGIN_NAMESPACE
@@ -31,9 +32,8 @@ class QQmlContext;
class Q_AUTOTEST_EXPORT QQuickStyledTextImgTag
{
public:
- QQuickStyledTextImgTag() { }
-
- ~QQuickStyledTextImgTag() { delete pix; }
+ QQuickStyledTextImgTag() = default;
+ ~QQuickStyledTextImgTag() = default;
enum Align {
Bottom,
@@ -47,7 +47,7 @@ public:
int position = 0;
qreal offset = 0.0; // this offset allows us to compensate for flooring reserved space
Align align = QQuickStyledTextImgTag::Bottom;
- QQuickPixmap *pix = nullptr;
+ QScopedPointer<QQuickPixmap> pix;
};
class Q_AUTOTEST_EXPORT QQuickStyledText
diff --git a/src/quick/util/qquickvaluetypes.cpp b/src/quick/util/qquickvaluetypes.cpp
index 4f4f893d83..265c763566 100644
--- a/src/quick/util/qquickvaluetypes.cpp
+++ b/src/quick/util/qquickvaluetypes.cpp
@@ -763,6 +763,135 @@ bool QQuickMatrix4x4ValueType::fuzzyEquals(const QMatrix4x4 &m) const
return qFuzzyCompare(v, m);
}
+/*!
+ \qmltype PlanarTransform
+ \inqmlmodule QtQuick
+ \since 6.8
+
+ \brief Provides utility functions for matrix4x4 when used for 2D transforms.
+
+ The \c PlanarTransform is a global object with utility functions.
+
+ It is not instantiable; to use it, call the members of the global \c PlanarTransform object
+ directly. For example:
+
+ \qml
+ Item {
+ transform: Matrix4x4 { matrix: PlanarTransform.fromAffineMatrix(1, 0, 0.36, 1, -36, 0) }
+ }
+ \endqml
+*/
+
+QQuickPlanarTransform::QQuickPlanarTransform(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ \qmlmethod matrix4x4 PlanarTransform::identity()
+
+ Returns a matrix4x4 for the identity transform.
+
+ This is equivalent to \l Qt::matrix4x4().
+*/
+
+QMatrix4x4 QQuickPlanarTransform::identity()
+{
+ return QMatrix4x4();
+}
+
+/*!
+ \qmlmethod matrix4x4 PlanarTransform::fromAffineMatrix(real scaleX, real shearY,
+ real shearX, real scaleY,
+ real translateX, real translateY)
+
+ Returns a matrix4x4 for an affine (non-projecting) 2D transform with the specified values.
+
+ This method and its argument order correspond to SVG's \c matrix() function and the
+ six-argument QTransform constructor. The result is this 4x4 matrix:
+
+ \table
+ \row \li \a scaleX \li \a shearX \li 0 \li \a translateX
+ \row \li \a shearY \li \a scaleY \li 0 \li \a translateY
+ \row \li 0 \li 0 \li 1 \li 0
+ \row \li 0 \li 0 \li 0 \li 1
+ \endtable
+*/
+
+QMatrix4x4 QQuickPlanarTransform::fromAffineMatrix(float scaleX, float shearY,
+ float shearX, float scaleY,
+ float translateX, float translateY)
+{
+ return QMatrix4x4(scaleX, shearX, 0, translateX,
+ shearY, scaleY, 0, translateY,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1);
+}
+
+/*!
+ \qmlmethod matrix4x4 PlanarTransform::fromTranslate(real translateX, real translateY)
+
+ Returns a matrix4x4 for a 2D transform that translates by \a translateX horizontally and
+ \a translateY vertically.
+*/
+QMatrix4x4 QQuickPlanarTransform::fromTranslate(float translateX, float translateY)
+{
+ QMatrix4x4 xf;
+ xf.translate(translateX, translateY);
+ return xf;
+}
+
+/*!
+ \qmlmethod matrix4x4 PlanarTransform::fromScale(real scaleX, real scaleY, real originX, real originY)
+
+ Returns a matrix4x4 for a 2D transform that scales by \a scaleX horizontally and \a scaleY
+ vertically, centered at the point (\a originX, \a originY).
+
+ \a originX and \a originY are optional and default to (0, 0).
+*/
+QMatrix4x4 QQuickPlanarTransform::fromScale(float scaleX, float scaleY, float originX, float originY)
+{
+ QMatrix4x4 xf;
+ xf.translate(originX, originY);
+ xf.scale(scaleX, scaleY);
+ xf.translate(-originX, -originY);
+ return xf;
+}
+
+/*!
+ \qmlmethod matrix4x4 PlanarTransform::fromRotate(real angle, real originX, real originY)
+
+ Returns a matrix4x4 for a 2D transform that rotates by \a angle degrees around the point (\a
+ originX, \a originY).
+
+ \a originX and \a originY are optional and default to (0, 0).
+*/
+QMatrix4x4 QQuickPlanarTransform::fromRotate(float angle, float originX, float originY)
+{
+ QMatrix4x4 xf;
+ xf.translate(originX, originY);
+ xf.rotate(angle, 0, 0, 1);
+ xf.translate(-originX, -originY);
+ return xf;
+}
+
+/*!
+ \qmlmethod matrix4x4 PlanarTransform::fromShear(float shearX, float shearY, float originX, float originY)
+
+ Returns a matrix4x4 for a 2D transform that shears by \a shearX horizontally and \a shearY
+ vertically, centered at the point (\a originX, \a originY).
+
+ \a originX and \a originY are optional and default to (0, 0).
+*/
+QMatrix4x4 QQuickPlanarTransform::fromShear(float shearX, float shearY, float originX, float originY)
+{
+ QMatrix4x4 xf;
+ xf.translate(originX, originY);
+ xf *= QMatrix4x4(1, shearX, 0, 0, shearY, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ xf.translate(-originX, -originY);
+ return xf;
+}
+
template<typename T>
void setFontProperty(QFont &font, void (QFont::*setter)(T value), QString name,
const QJSValue &params, bool *ok)
@@ -809,27 +938,45 @@ QVariant QQuickFontValueType::create(const QJSValue &params)
setFontProperty(ret, &QFont::setPixelSize, QStringLiteral("pixelSize"), params, &ok);
setFontProperty(ret, &QFont::setPointSize, QStringLiteral("pointSize"), params, &ok);
setFontProperty(ret, &QFont::setStrikeOut, QStringLiteral("strikeout"), params, &ok);
+ setFontProperty(ret, &QFont::setStyleName, QStringLiteral("styleName"), params, &ok);
setFontProperty(ret, &QFont::setUnderline, QStringLiteral("underline"), params, &ok);
setFontProperty(ret, &QFont::setWeight, QStringLiteral("weight"), params, &ok);
setFontProperty(ret, &QFont::setWordSpacing, QStringLiteral("wordSpacing"), params, &ok);
setFontProperty(ret, &QFont::setHintingPreference, QStringLiteral("hintingPreference"), params, &ok);
setFontProperty(ret, &QFont::setKerning, QStringLiteral("kerning"), params, &ok);
- const QJSValue vlspac = params.property(QStringLiteral("letterSpacing"));
- if (vlspac.isNumber()) {
- ret.setLetterSpacing(QFont::AbsoluteSpacing, vlspac.toNumber());
- ok = true;
+ {
+ const QJSValue vlspac = params.property(QStringLiteral("letterSpacing"));
+ if (vlspac.isNumber()) {
+ ret.setLetterSpacing(QFont::AbsoluteSpacing, vlspac.toNumber());
+ ok = true;
+ }
+ }
+
+ {
+ const QJSValue vshaping = params.property(QStringLiteral("preferShaping"));
+ if (vshaping.isBool()) {
+ const bool enable = vshaping.toBool();
+ const QFont::StyleStrategy strategy = ret.styleStrategy();
+ if (enable)
+ ret.setStyleStrategy(QFont::StyleStrategy(strategy & ~QFont::PreferNoShaping));
+ else
+ ret.setStyleStrategy(QFont::StyleStrategy(strategy | QFont::PreferNoShaping));
+ ok = true;
+ }
}
- const QJSValue vshaping = params.property(QStringLiteral("preferShaping"));
- if (vshaping.isBool()) {
- const bool enable = vshaping.toBool();
- const QFont::StyleStrategy strategy = ret.styleStrategy();
- if (enable)
- ret.setStyleStrategy(QFont::StyleStrategy(strategy & ~QFont::PreferNoShaping));
- else
- ret.setStyleStrategy(QFont::StyleStrategy(strategy | QFont::PreferNoShaping));
- ok = true;
+ {
+ const QJSValue typoMetrics = params.property(QStringLiteral("preferTypoLineMetrics"));
+ if (typoMetrics.isBool()) {
+ const bool enable = typoMetrics.toBool();
+ const QFont::StyleStrategy strategy = ret.styleStrategy();
+ if (enable)
+ ret.setStyleStrategy(QFont::StyleStrategy(strategy & ~QFont::PreferTypoLineMetrics));
+ else
+ ret.setStyleStrategy(QFont::StyleStrategy(strategy | QFont::PreferTypoLineMetrics));
+ ok = true;
+ }
}
return ok ? ret : QVariant();
@@ -1080,6 +1227,32 @@ QVariantMap QQuickFontValueType::features() const
return ret;
}
+bool QQuickFontValueType::contextFontMerging() const
+{
+ return (v.styleStrategy() & QFont::ContextFontMerging) != 0;
+}
+
+void QQuickFontValueType::setContextFontMerging(bool enable)
+{
+ if (enable)
+ v.setStyleStrategy(static_cast<QFont::StyleStrategy>(v.styleStrategy() | QFont::ContextFontMerging));
+ else
+ v.setStyleStrategy(static_cast<QFont::StyleStrategy>(v.styleStrategy() & ~QFont::ContextFontMerging));
+}
+
+bool QQuickFontValueType::preferTypoLineMetrics() const
+{
+ return (v.styleStrategy() & QFont::PreferTypoLineMetrics) != 0;
+}
+
+void QQuickFontValueType::setPreferTypoLineMetrics(bool enable)
+{
+ if (enable)
+ v.setStyleStrategy(static_cast<QFont::StyleStrategy>(v.styleStrategy() | QFont::PreferTypoLineMetrics));
+ else
+ v.setStyleStrategy(static_cast<QFont::StyleStrategy>(v.styleStrategy() & ~QFont::PreferTypoLineMetrics));
+}
+
QVariant QQuickColorSpaceValueType::create(const QJSValue &params)
{
if (!params.isObject())
diff --git a/src/quick/util/qquickvaluetypes_p.h b/src/quick/util/qquickvaluetypes_p.h
index 08491c633b..6fd33c1323 100644
--- a/src/quick/util/qquickvaluetypes_p.h
+++ b/src/quick/util/qquickvaluetypes_p.h
@@ -54,6 +54,7 @@ class Q_QUICK_EXPORT QQuickColorValueType
public:
static QVariant create(const QJSValue &params);
+ Q_INVOKABLE QQuickColorValueType() = default;
Q_INVOKABLE QQuickColorValueType(const QString &string);
Q_INVOKABLE QString toString() const;
@@ -102,6 +103,7 @@ class Q_QUICK_EXPORT QQuickVector2DValueType
public:
static QVariant create(const QJSValue &params);
+ Q_INVOKABLE QQuickVector2DValueType() = default;
Q_INVOKABLE QString toString() const;
qreal x() const;
@@ -140,6 +142,7 @@ class Q_QUICK_EXPORT QQuickVector3DValueType
public:
static QVariant create(const QJSValue &params);
+ Q_INVOKABLE QQuickVector3DValueType() = default;
Q_INVOKABLE QString toString() const;
qreal x() const;
@@ -183,6 +186,7 @@ class Q_QUICK_EXPORT QQuickVector4DValueType
public:
static QVariant create(const QJSValue &params);
+ Q_INVOKABLE QQuickVector4DValueType() = default;
Q_INVOKABLE QString toString() const;
qreal x() const;
@@ -227,6 +231,7 @@ class Q_QUICK_EXPORT QQuickQuaternionValueType
public:
static QVariant create(const QJSValue &params);
+ Q_INVOKABLE QQuickQuaternionValueType() = default;
Q_INVOKABLE QString toString() const;
qreal scalar() const;
@@ -288,6 +293,8 @@ class Q_QUICK_EXPORT QQuickMatrix4x4ValueType
public:
static QVariant create(const QJSValue &params);
+ Q_INVOKABLE QQuickMatrix4x4ValueType() = default;
+
qreal m11() const { return v(0, 0); }
qreal m12() const { return v(0, 1); }
qreal m13() const { return v(0, 2); }
@@ -353,6 +360,28 @@ public:
operator QMatrix4x4() const { return v; }
};
+class Q_QUICK_EXPORT QQuickPlanarTransform : public QObject
+{
+ Q_OBJECT
+ QML_SINGLETON
+ QML_NAMED_ELEMENT(PlanarTransform)
+ QML_ADDED_IN_VERSION(6, 8)
+
+public:
+ explicit QQuickPlanarTransform(QObject *parent = nullptr);
+
+ Q_INVOKABLE static QMatrix4x4 identity();
+ Q_INVOKABLE static QMatrix4x4 fromAffineMatrix(float scaleX, float shearY,
+ float shearX, float scaleY,
+ float translateX, float translateY);
+ Q_INVOKABLE static QMatrix4x4 fromTranslate(float translateX, float translateY);
+ Q_INVOKABLE static QMatrix4x4 fromScale(float scaleX, float scaleY,
+ float originX = 0, float originY = 0);
+ Q_INVOKABLE static QMatrix4x4 fromRotate(float angle,float originX = 0, float originY = 0);
+ Q_INVOKABLE static QMatrix4x4 fromShear(float shearX, float shearY,
+ float originX = 0, float originY = 0);
+};
+
namespace QQuickFontEnums
{
Q_NAMESPACE_EXPORT(Q_QUICK_EXPORT)
@@ -409,6 +438,8 @@ class Q_QUICK_EXPORT QQuickFontValueType
Q_PROPERTY(bool preferShaping READ preferShaping WRITE setPreferShaping FINAL)
Q_PROPERTY(QVariantMap features READ features WRITE setFeatures FINAL)
Q_PROPERTY(QVariantMap variableAxes READ variableAxes WRITE setVariableAxes FINAL)
+ Q_PROPERTY(bool contextFontMerging READ contextFontMerging WRITE setContextFontMerging FINAL)
+ Q_PROPERTY(bool preferTypoLineMetrics READ preferTypoLineMetrics WRITE setPreferTypoLineMetrics FINAL)
QML_VALUE_TYPE(font)
QML_FOREIGN(QFont)
@@ -419,6 +450,7 @@ class Q_QUICK_EXPORT QQuickFontValueType
public:
static QVariant create(const QJSValue &value);
+ Q_INVOKABLE QQuickFontValueType() = default;
Q_INVOKABLE QString toString() const;
QString family() const;
@@ -475,6 +507,12 @@ public:
QVariantMap variableAxes() const;
void setVariableAxes(const QVariantMap &variableAxes);
+ bool contextFontMerging() const;
+ void setContextFontMerging(bool b);
+
+ bool preferTypoLineMetrics() const;
+ void setPreferTypoLineMetrics(bool b);
+
operator QFont() const { return v; }
};
diff --git a/src/quickcontrols/CMakeLists.txt b/src/quickcontrols/CMakeLists.txt
index 18b170ad82..ea98c45908 100644
--- a/src/quickcontrols/CMakeLists.txt
+++ b/src/quickcontrols/CMakeLists.txt
@@ -17,6 +17,7 @@ qt_internal_add_qml_module(QuickControls2
QtQuick.Controls.Material/auto
QtQuick.Controls.Imagine/auto
QtQuick.Controls.Universal/auto
+ QtQuick.Controls.FluentWinUI3/auto
QtQuick.Controls.Windows/auto
QtQuick.Controls.macOS/auto
QtQuick.Controls.iOS/auto
@@ -83,6 +84,10 @@ if(QT_FEATURE_quickcontrols2_universal)
add_subdirectory(universal)
endif()
+if(QT_FEATURE_quickcontrols2_fluentwinui3)
+ add_subdirectory(fluentwinui3)
+endif()
+
if(QT_FEATURE_quickcontrols2_macos)
add_subdirectory(macos)
endif()
diff --git a/src/quickcontrols/basic/ComboBox.qml b/src/quickcontrols/basic/ComboBox.qml
index 5c71a4398e..91774afc42 100644
--- a/src/quickcontrols/basic/ComboBox.qml
+++ b/src/quickcontrols/basic/ComboBox.qml
@@ -85,6 +85,7 @@ T.ComboBox {
height: Math.min(contentItem.implicitHeight, control.Window.height - topMargin - bottomMargin)
topMargin: 6
bottomMargin: 6
+ palette: control.palette
contentItem: ListView {
clip: true
diff --git a/src/quickcontrols/configure.cmake b/src/quickcontrols/configure.cmake
index b146186426..4405a9f915 100644
--- a/src/quickcontrols/configure.cmake
+++ b/src/quickcontrols/configure.cmake
@@ -44,6 +44,12 @@ qt_feature("quickcontrols2-universal" PRIVATE
PURPOSE "Provides a style based on the Universal Design guidelines."
CONDITION QT_FEATURE_quickcontrols2_basic
)
+qt_feature("quickcontrols2-fluentwinui3" PRIVATE
+ SECTION "Quick Controls 2"
+ LABEL "FluentWinUI3"
+ PURPOSE "Provides a style based on the Fluent design and Windows UI 3 style."
+ CONDITION QT_FEATURE_quickcontrols2_fusion
+)
qt_feature("quickcontrols2-macos" PRIVATE
SECTION "Quick Controls 2"
LABEL "macOS"
@@ -65,7 +71,7 @@ qt_feature("quickcontrols2-windows" PRIVATE
qt_configure_add_summary_section(NAME "Qt Quick Controls 2")
qt_configure_add_summary_entry(
TYPE "featureList"
- ARGS "quickcontrols2-basic quickcontrols2-fusion quickcontrols2-imagine quickcontrols2-ios quickcontrols2-material quickcontrols2-universal quickcontrols2-macos quickcontrols2-windows"
+ ARGS "quickcontrols2-basic quickcontrols2-fusion quickcontrols2-fluentwinui3 quickcontrols2-imagine quickcontrols2-ios quickcontrols2-material quickcontrols2-universal quickcontrols2-macos quickcontrols2-windows"
MESSAGE "Styles"
)
qt_configure_end_summary_section() # end of "Qt Quick Controls 2" section
diff --git a/src/quickcontrols/doc/images/qtquickcontrols-menu-native.png b/src/quickcontrols/doc/images/qtquickcontrols-menu-native.png
new file mode 100644
index 0000000000..b7812bf31f
--- /dev/null
+++ b/src/quickcontrols/doc/images/qtquickcontrols-menu-native.png
Binary files differ
diff --git a/src/quickcontrols/doc/images/qtquickcontrols-menu.png b/src/quickcontrols/doc/images/qtquickcontrols-menu.png
index 926c33eed2..11f69cf5e5 100644
--- a/src/quickcontrols/doc/images/qtquickcontrols-menu.png
+++ b/src/quickcontrols/doc/images/qtquickcontrols-menu.png
Binary files differ
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-busyindicator-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-busyindicator-custom.qml
index 951976210a..7e57e6bbe7 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-busyindicator-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-busyindicator-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
BusyIndicator {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-button-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-button-custom.qml
index c9778faa3b..13ac86e549 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-button-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-button-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Button {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-checkbox-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-checkbox-custom.qml
index d3c2f98ec1..1cc413aae3 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-checkbox-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-checkbox-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
CheckBox {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-checkdelegate-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-checkdelegate-custom.qml
index d2d8c622d5..2cee3313eb 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-checkdelegate-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-checkdelegate-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
CheckDelegate {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-combobox-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-combobox-custom.qml
index ff499f6550..0cc408d492 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-combobox-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-combobox-custom.qml
@@ -5,7 +5,7 @@
pragma ComponentBehavior: Bound
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ComboBox {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-delaybutton-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-delaybutton-custom.qml
index 1803556052..861c558e3c 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-delaybutton-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-delaybutton-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
DelayButton {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-dial-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-dial-custom.qml
index 65a7439ea1..06399a318a 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-dial-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-dial-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Dial {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-frame-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-frame-custom.qml
index 51dd757044..8498d9bae2 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-frame-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-frame-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Frame {
background: Rectangle {
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-groupbox-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-groupbox-custom.qml
index 38c0f03366..675e2d5e47 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-groupbox-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-groupbox-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
GroupBox {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate-custom.qml
index 8dcc860dd7..5e299a9d8f 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ItemDelegate {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-label-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-label-custom.qml
index 0443e4e357..291d04948f 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-label-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-label-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Label {
text: qsTr("Label")
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-menu-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-menu-custom.qml
index 6d1c587f74..a0b59adffd 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-menu-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-menu-custom.qml
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ApplicationWindow {
id: window
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-menubar-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-menubar-custom.qml
index d76f4f56cd..ef55a5f4c2 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-menubar-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-menubar-custom.qml
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ApplicationWindow {
id: window
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-menuseparator-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-menuseparator-custom.qml
index 81c1e7a7f5..fbc024aa57 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-menuseparator-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-menuseparator-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Item {
id: window
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-pageindicator-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-pageindicator-custom.qml
index 93c2045fc3..14b4131c75 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-pageindicator-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-pageindicator-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
PageIndicator {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-pane-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-pane-custom.qml
index 4663ae9138..aca3f73dc6 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-pane-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-pane-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Pane {
background: Rectangle {
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-popup-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-popup-custom.qml
index bf054f0b3a..cae29d238d 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-popup-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-popup-custom.qml
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
import QtQuick.Window
Item {
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-progressbar-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-progressbar-custom.qml
index ebfbaff62e..97cad51926 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-progressbar-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-progressbar-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ProgressBar {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-radiobutton-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-radiobutton-custom.qml
index 731c67f6b2..3fa1659eec 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-radiobutton-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-radiobutton-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
RadioButton {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-radiodelegate-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-radiodelegate-custom.qml
index 93feeeeece..55c571fab1 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-radiodelegate-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-radiodelegate-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
RadioDelegate {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-rangeslider-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-rangeslider-custom.qml
index 86e71b3175..a83ebe8240 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-rangeslider-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-rangeslider-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
RangeSlider {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-scrollbar-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-scrollbar-custom.qml
index 5ad266dc93..d97627f083 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-scrollbar-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-scrollbar-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ScrollBar {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-scrollindicator-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-scrollindicator-custom.qml
index 8c517b8221..c46832b2c3 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-scrollindicator-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-scrollindicator-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ScrollIndicator {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-scrollview-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-scrollview-custom.qml
index 4c1ec3d29a..05c4ce413e 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-scrollview-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-scrollview-custom.qml
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Item {
width: 200
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-slider-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-slider-custom.qml
index dad6beaa86..26565d3987 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-slider-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-slider-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Slider {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-spinbox-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-spinbox-custom.qml
index c2e6452da6..20b149d611 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-spinbox-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-spinbox-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
SpinBox {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-splitview-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-splitview-custom.qml
index c713c9623d..bb2c29ac6a 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-splitview-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-splitview-custom.qml
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Item {
width: 200
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-stackview-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-stackview-custom.qml
index ec4db1c2de..2f0ea85c77 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-stackview-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-stackview-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
StackView {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-swipedelegate-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-swipedelegate-custom.qml
index 4382e5f9ec..eb691bc9d3 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-swipedelegate-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-swipedelegate-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
SwipeDelegate {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-swipeview-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-swipeview-custom.qml
index 3eae7c28d5..cad89faa06 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-swipeview-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-swipeview-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
SwipeView {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-switch-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-switch-custom.qml
index 6f0cac5b67..c905d4c122 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-switch-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-switch-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Switch {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-switchdelegate-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-switchdelegate-custom.qml
index 2df83b936f..605e5476d5 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-switchdelegate-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-switchdelegate-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
SwitchDelegate {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-tabbar-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-tabbar-custom.qml
index 0310900c42..4017553ef9 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-tabbar-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-tabbar-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
TabBar {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-textarea-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-textarea-custom.qml
index e264a921bb..700cebafe1 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-textarea-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-textarea-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
TextArea {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-textfield-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-textfield-custom.qml
index bed0e25173..740e226662 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-textfield-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-textfield-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
TextField {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-toolbar-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-toolbar-custom.qml
index e4ea2c8b04..75e8f11778 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-toolbar-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-toolbar-custom.qml
@@ -3,7 +3,7 @@
import QtQuick
import QtQuick.Layouts
-import QtQuick.Controls
+import QtQuick.Controls.Basic
//! [file]
ToolBar {
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-toolbutton-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-toolbutton-custom.qml
index ed2c7aaf64..ea81bc9766 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-toolbutton-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-toolbutton-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ToolButton {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-toolseparator-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-toolseparator-custom.qml
index 120428801a..28de544242 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-toolseparator-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-toolseparator-custom.qml
@@ -4,7 +4,7 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
-import QtQuick.Controls
+import QtQuick.Controls.Basic
//! [file]
ToolBar {
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-custom.qml
index 04e390a611..cde93b1abd 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Item {
ToolTip {
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-tumbler-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-tumbler-custom.qml
index d3dbcf7acc..ee94097acd 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-tumbler-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-tumbler-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Tumbler {
id: control
diff --git a/src/quickcontrols/doc/src/includes/qquickheaderview.qdocinc b/src/quickcontrols/doc/src/includes/qquickheaderview.qdocinc
index 5115149762..fdc191be3f 100644
--- a/src/quickcontrols/doc/src/includes/qquickheaderview.qdocinc
+++ b/src/quickcontrols/doc/src/includes/qquickheaderview.qdocinc
@@ -84,3 +84,21 @@ The warning can be silenced by setting the \l textRole.
\sa QAbstractItemModel::roleNames()
//! [textRole]
+
+//! [movableColumns]
+This property allows the user to move columns in the view. The default value is
+\c false.
+
+\note If this property is set, the HorizontalHeaderView allows the user to drag
+and drop columns at the required position. When syncView is enabled,
+any change will be applied to the corresponding view item.
+//! [movableColumns]
+
+//! [movableRows]
+This property allows the user to move rows in the view. The default value is \c
+false.
+
+\note If this property is set, the VerticalHeaderView allows the user to drag
+and drop rows at the required position. When syncView is enabled,
+any change will be applied to the corresponding view item.
+//! [movableRows]
diff --git a/src/quickcontrols/doc/src/includes/qquickmenu.qdocinc b/src/quickcontrols/doc/src/includes/qquickmenu.qdocinc
new file mode 100644
index 0000000000..86a65338e5
--- /dev/null
+++ b/src/quickcontrols/doc/src/includes/qquickmenu.qdocinc
@@ -0,0 +1,4 @@
+//! [non-native-only-property]
+\note This property is only supported when using a
+\l {Native Menus}{non-native Menu}.
+//! [non-native-only-property]
diff --git a/src/quickcontrols/doc/src/qtquickcontrols-customize.qdoc b/src/quickcontrols/doc/src/qtquickcontrols-customize.qdoc
index 5c93e43441..1f12b72822 100644
--- a/src/quickcontrols/doc/src/qtquickcontrols-customize.qdoc
+++ b/src/quickcontrols/doc/src/qtquickcontrols-customize.qdoc
@@ -557,7 +557,7 @@
\code
import QtQuick
- import QtQuick.Controls
+ import QtQuick.Controls.Basic
ApplicationWindow {
visible: true
@@ -728,7 +728,7 @@
\quotefromfile qtquickcontrols-menu-custom.qml
\skipto import QtQuick
- \printuntil import QtQuick.Controls
+ \printuntil import QtQuick.Controls.Basic
\skipto Menu
\printto eof
@@ -743,7 +743,7 @@
\quotefromfile qtquickcontrols-menubar-custom.qml
\skipto import QtQuick
- \printuntil import QtQuick.Controls
+ \printuntil import QtQuick.Controls.Basic
\skipto MenuBar
\printto eof
@@ -775,7 +775,7 @@
\quotefromfile qtquickcontrols-popup-custom.qml
\skipto import QtQuick
- \printuntil import QtQuick.Controls
+ \printuntil import QtQuick.Controls.Basic
\codeline
\skipto Popup
\printuntil {
@@ -1013,7 +1013,7 @@
\quotefromfile qtquickcontrols-tooltip-custom.qml
\skipto import QtQuick
- \printuntil import QtQuick.Controls
+ \printuntil import QtQuick.Controls.Basic
\skipto ToolTip
\printuntil }
\printuntil }
diff --git a/src/quickcontrols/fluentwinui3/ApplicationWindow.qml b/src/quickcontrols/fluentwinui3/ApplicationWindow.qml
new file mode 100644
index 0000000000..2ed493f7bb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/ApplicationWindow.qml
@@ -0,0 +1,12 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ApplicationWindow {
+ id: window
+
+ color: window.palette.window
+}
diff --git a/src/quickcontrols/fluentwinui3/Button.qml b/src/quickcontrols/fluentwinui3/Button.qml
new file mode 100644
index 0000000000..bd04123b2d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/Button.qml
@@ -0,0 +1,59 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Button {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ spacing: config.spacing || 0
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ icon.width: 16
+ icon.height: 16
+ icon.color: (control.checked || control.highlighted)
+ ? (control.down ? (Qt.styleHints.colorScheme == Qt.Light ? "#7FFFFFFF" : "#80000000") //textOnAccentSecondary
+ : control.palette.highlightedText)
+ : (control.down ? control.palette.brightText : control.palette.buttonText)
+
+ readonly property string __currentState: [
+ (control.checked || control.highlighted) && "checked",
+ !control.enabled && "disabled",
+ control.enabled && !control.down && control.hovered && "hovered",
+ control.down && "pressed"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: (control.flat && Config.controls.flatbutton
+ ? Config.controls.flatbutton[__currentState]
+ : Config.controls.button[__currentState]) || {}
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.config.label.textVAlignment | control.config.label.textHAlignment
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.icon.color
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/CMakeLists.txt b/src/quickcontrols/fluentwinui3/CMakeLists.txt
new file mode 100644
index 0000000000..5ec321ae2d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/CMakeLists.txt
@@ -0,0 +1,69 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## qtquickcontrols2fluentwinui3styleplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "ApplicationWindow.qml"
+ "Button.qml"
+ "CheckBox.qml"
+ "ProgressBar.qml"
+ "RadioButton.qml"
+ "RangeSlider.qml"
+ "Slider.qml"
+ "Switch.qml"
+ "TextField.qml"
+ "TextArea.qml"
+ "Config.qml" # TODO: move to impl module
+ "StyleImage.qml" # TODO: move to impl module
+)
+
+set_source_files_properties(Config.qml PROPERTIES
+ QT_QML_SINGLETON_TYPE TRUE
+)
+
+file(GLOB light_theme_resources RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "light/images/*.png")
+file(GLOB dark_theme_resources RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "dark/images/*.png")
+
+add_subdirectory(impl)
+
+qt_internal_add_qml_module(qtquickcontrols2fluentwinui3styleplugin
+ URI "QtQuick.Controls.FluentWinUI3"
+ VERSION "${PROJECT_VERSION}"
+ PAST_MAJOR_VERSIONS 2
+ CLASS_NAME QtQuickControls2FluentWinUI3StylePlugin
+ IMPORTS
+ QtQuick.Controls.Fusion/auto
+ PLUGIN_TARGET qtquickcontrols2fluentwinui3styleplugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ SOURCES
+ qtquickcontrols2fluentwinui3styleplugin.cpp
+ qquickfluentwinui3theme_p.h qquickfluentwinui3theme.cpp
+ QML_FILES
+ ${qml_files}
+ RESOURCES
+ ${light_theme_resources}
+ ${dark_theme_resources}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickControls2FluentWinUI3StyleImpl
+ Qt::QuickControls2ImplPrivate
+ Qt::QuickControls2Private
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
+
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2fluentwinui3styleplugin
+ qtquickcontrols2fluentwinui3styleimplplugin)
+
+# Fusion style is the required fallback style.
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2fluentwinui3styleplugin
+ qtquickcontrols2fusionstyleplugin)
diff --git a/src/quickcontrols/fluentwinui3/CheckBox.qml b/src/quickcontrols/fluentwinui3/CheckBox.qml
new file mode 100644
index 0000000000..52d7efde42
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/CheckBox.qml
@@ -0,0 +1,61 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.CheckBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: config.spacing || 0
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: [
+ control.checkState === Qt.Checked && "checked",
+ !control.enabled && "disabled",
+ control.enabled && !control.down && control.hovered && "hovered",
+ control.checkState === Qt.PartiallyChecked && "partiallyChecked",
+ control.down && "pressed",
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.checkbox[__currentState] || {}
+ readonly property bool mirroredIndicator: control.mirrored !== (config.mirrored || false)
+
+ // TODO: Add animation for indicator
+ indicator: Image {
+ x: control.text ? (control.mirroredIndicator ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ source: Qt.resolvedUrl(control.config.indicator.filePath)
+ }
+
+ contentItem: Text {
+ leftPadding: control.indicator && !control.mirroredIndicator ? control.indicator.width + control.spacing : 0
+ rightPadding: control.indicator && control.mirroredIndicator ? control.indicator.width + control.spacing : 0
+
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/Config.qml b/src/quickcontrols/fluentwinui3/Config.qml
new file mode 100644
index 0000000000..d6ec3e0f9c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/Config.qml
@@ -0,0 +1,9920 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+pragma Singleton
+import QtQml
+
+QtObject {
+ readonly property QtObject controls: Qt.styleHints.colorScheme === Qt.Light ? light.controls : dark.controls
+
+ readonly property QtObject dark: QtObject {
+ readonly property QtObject controls: QtObject {
+ readonly property QtObject button: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17023;8603:12521;2373:10903"
+ readonly property string filePath: "dark/images/button-background-checked.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 1874
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17023;8603:12521"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17023;8603:12521;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 1881
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17023;8603:12521;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 1879
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17029;8603:12527;2373:10903"
+ readonly property string filePath: "dark/images/button-background-checked-disabled.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2075
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17029;8603:12527"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17029;8603:12527;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2082
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17029;8603:12527;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2080
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17027;8603:12525;2373:10903"
+ readonly property string filePath: "dark/images/button-background-checked-hovered.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2008
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17027;8603:12525"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17027;8603:12525;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2015
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17027;8603:12525;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2013
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17031;8603:12529;2373:10903"
+ readonly property string filePath: "dark/images/button-background-checked-pressed.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2142
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17031;8603:12529"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17031;8603:12529;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2149
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17031;8603:12529;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2147
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17025;8603:12523;2373:10903"
+ readonly property string filePath: "dark/images/button-background-disabled.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 1941
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17025;8603:12523"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17025;8603:12523;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 1948
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17025;8603:12523;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 1946
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17019;8603:12517;2373:10903"
+ readonly property string filePath: "dark/images/button-background-hovered.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 1740
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17019;8603:12517"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17019;8603:12517;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 1747
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17019;8603:12517;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 1745
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17017;8603:12515;2373:10903"
+ readonly property string filePath: "dark/images/button-background.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2227.5
+ readonly property real y: 1685
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17017;8603:12515"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17017;8603:12515;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2247.5
+ readonly property real y: 1692
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17017;8603:12515;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2271.5
+ readonly property real y: 1690
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17021;8603:12519;2373:10903"
+ readonly property string filePath: "dark/images/button-background-pressed.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 1807
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17021;8603:12519"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17021;8603:12519;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 1814
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17021;8603:12519;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 1812
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject checkbox: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17040;8622:13107;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2838.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17040;8622:13107"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17040;8622:13107;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-checked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2844.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17040;8622:13107;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2844.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17050;8622:13117;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 3114.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17050;8622:13117"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17050;8622:13117;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-checked-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 3120.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17050;8622:13117;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 3120.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17054;8622:13121;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2976.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17054;8622:13121"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17054;8622:13121;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-checked-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2982.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17054;8622:13121;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2982.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17052;8622:13119;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 3045.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17052;8622:13119"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17052;8622:13119;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-checked-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 3051.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17052;8622:13119;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 3051.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17056;8622:13123;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2907.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17056;8622:13123"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17056;8622:13123;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2913.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17056;8622:13123;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2913.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject disabled_partiallyChecked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17048;8622:13115;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-disabled-partiallyChecked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 3390.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17048;8622:13115"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-disabled-partiallyChecked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17048;8622:13115;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-disabled-partiallyChecked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-disabled-partiallyChecked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 3396.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17048;8622:13115;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-disabled-partiallyChecked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 3396.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17036;8622:13103;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2700.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17036;8622:13103"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17036;8622:13103;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2706.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17036;8622:13103;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2706.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered_partiallyChecked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17044;8622:13111;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-hovered-partiallyChecked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 3252.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17044;8622:13111"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-hovered-partiallyChecked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17044;8622:13111;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-hovered-partiallyChecked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-hovered-partiallyChecked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 3258.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17044;8622:13111;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-hovered-partiallyChecked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 3258.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17034;8622:13101;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2631.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17034;8622:13101"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17034;8622:13101;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2637.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17034;8622:13101;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2637.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject partiallyChecked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17042;8622:13109;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-partiallyChecked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 3183.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17042;8622:13109"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-partiallyChecked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17042;8622:13109;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-partiallyChecked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-partiallyChecked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 3189.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17042;8622:13109;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-partiallyChecked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 3189.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject partiallyChecked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17046;8622:13113;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-partiallyChecked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 3321.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17046;8622:13113"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-partiallyChecked-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17046;8622:13113;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-partiallyChecked-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-partiallyChecked-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 3327.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17046;8622:13113;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-partiallyChecked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 3327.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17038;8622:13105;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2769.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17038;8622:13105"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17038;8622:13105;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2775.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17038;8622:13105;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2775.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ }
+
+ readonly property QtObject flatbutton: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9227;3987:9104;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-checked.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 2040.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9227;3987:9104"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9227;3987:9104;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 2045.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9227;3987:9104;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 2045.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9230;3987:9122;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-checked-disabled.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked-disabled"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 2174.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9230;3987:9122"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9230;3987:9122;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 2179.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9230;3987:9122;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 2179.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9229;3987:9113;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-checked-hovered.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked-hovered"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 2107.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9229;3987:9113"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9229;3987:9113;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 2112.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9229;3987:9113;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 2112.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9231;3987:9131;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-checked-pressed.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked-pressed"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 2241.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9231;3987:9131"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9231;3987:9131;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 2246.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9231;3987:9131;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 2246.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9228;3987:9095;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-disabled.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-disabled"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 1973.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9228;3987:9095"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9228;3987:9095;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 1978.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9228;3987:9095;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 1978.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9225;3987:9077;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-hovered.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-hovered"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 1839.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9225;3987:9077"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9225;3987:9077;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 1844.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9225;3987:9077;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 1844.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9224;3987:9068;3987:9044"
+ readonly property string filePath: ""
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 1772.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9224;3987:9068"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9224;3987:9068;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 1777.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9224;3987:9068;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 1777.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9226;3987:9086;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-pressed.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-pressed"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 1906.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9226;3987:9086"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9226;3987:9086;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 1911.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9226;3987:9086;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 1911.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject progressbar: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9378;4304:9328"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem-disabled"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9378;4304:9328;4413:23724"
+ readonly property string filePath: "dark/images/progressbar-groove-disabled.png"
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15842
+ readonly property real y: 2059
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9378;4304:9328;4267:14564"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15842
+ readonly property real y: 2058
+ }
+
+ }
+
+ readonly property QtObject disabled_indeterminate: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9380;4304:9355"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem-disabled-indeterminate"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9380;4304:9355;4350:35746"
+ readonly property string filePath: ""
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove-disabled-indeterminate"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15842
+ readonly property real y: 2132
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9380;4304:9355;4403:22724"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track-disabled-indeterminate"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15908
+ readonly property real y: 2131
+ }
+
+ }
+
+ readonly property QtObject indeterminate: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9376;2450:12847"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem-indeterminate"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9376;2450:12847;4350:35746"
+ readonly property string filePath: ""
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove-indeterminate"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15842
+ readonly property real y: 1986
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9376;2450:12847;4403:22724"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track-indeterminate"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15908
+ readonly property real y: 1985
+ }
+
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9374;2450:12841"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9374;2450:12841;4413:23724"
+ readonly property string filePath: "dark/images/progressbar-groove.png"
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15842
+ readonly property real y: 1913
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9374;2450:12841;4267:14564"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15842
+ readonly property real y: 1912
+ }
+
+ }
+
+ }
+
+ readonly property QtObject radiobutton: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17135;2483:15472;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 1977.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17135;2483:15472"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17135;2483:15472;2473:12871"
+ readonly property string filePath: "dark/images/radiobutton-indicator-checked.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 1983.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17135;2483:15472;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 1985.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17141;2488:15512;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 2255.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17141;2488:15512"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17141;2488:15512;2473:12871"
+ readonly property string filePath: "dark/images/radiobutton-indicator-checked-disabled.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 2261.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17141;2488:15512;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 2263.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17137;8622:14986"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 2119.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17137;8622:14985"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17137;8622:14996"
+ readonly property string filePath: "dark/images/radiobutton-indicator-checked-hovered.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 2125.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17137;8622:14988"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 2127.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17139;8622:15023"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 2186.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17139;8622:15022"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17139;8622:15033"
+ readonly property string filePath: "dark/images/radiobutton-indicator-checked-pressed.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 2192.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17139;8622:15025"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 2194.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17143;2483:15480;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 2048.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17143;2483:15480"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17143;2483:15480;2473:12871"
+ readonly property string filePath: "dark/images/radiobutton-indicator-disabled.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 2054.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17143;2483:15480;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 2056.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17131;2473:12899;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 1839.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17131;2473:12899"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17131;2473:12899;2473:12871"
+ readonly property string filePath: "dark/images/radiobutton-indicator-hovered.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 1845.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17131;2473:12899;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 1847.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17129;2473:12891;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 1770.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17129;2473:12891"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17129;2473:12891;2473:12871"
+ readonly property string filePath: "dark/images/radiobutton-indicator.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 1776.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17129;2473:12891;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 1778.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17133;8622:15060"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 1908.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17133;8622:15059"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17133;8622:15070"
+ readonly property string filePath: "dark/images/radiobutton-indicator-pressed.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 1914.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17133;8622:15062"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 1916.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ }
+
+ readonly property QtObject rangeslider: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17152;2509:12481;2509:12419"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17964
+ readonly property real y: 2839
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17152;2509:12481"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17152;2509:12481;4189:38496"
+ readonly property string filePath: "dark/images/rangeslider-first-handle-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-first-handle-disabled"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 17992
+ readonly property real y: 2839
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17152;2509:12481;4178:28261"
+ readonly property string filePath: "dark/images/rangeslider-groove-disabled.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17972
+ readonly property real y: 2847
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17152;2509:12481;4191:43003"
+ readonly property string filePath: "dark/images/rangeslider-second-handle-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-second-handle-disabled"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 18116
+ readonly property real y: 2839
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17152;2509:12481;4189:38505"
+ readonly property string filePath: "dark/images/rangeslider-track-disabled.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 18002
+ readonly property real y: 2847
+ }
+
+ }
+
+ readonly property QtObject handle_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17150;8624:14526"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background-handle-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17964
+ readonly property real y: 2781
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17150;8624:14525"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem-handle-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17150;8624:14556"
+ readonly property string filePath: "dark/images/rangeslider-first-handle-handle-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-first-handle-handle-pressed"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 17992
+ readonly property real y: 2781
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17150;8624:14529"
+ readonly property string filePath: "dark/images/rangeslider-groove-handle-pressed.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove-handle-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17972
+ readonly property real y: 2789
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17150;8624:14627"
+ readonly property string filePath: "dark/images/rangeslider-second-handle-handle-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-second-handle-handle-pressed"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 18116
+ readonly property real y: 2781
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17150;8624:14531"
+ readonly property string filePath: "dark/images/rangeslider-track-handle-pressed.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track-handle-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 18002
+ readonly property real y: 2789
+ }
+
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17148;8624:14397"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17964
+ readonly property real y: 2723
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17148;8624:14396"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17148;8624:14427"
+ readonly property string filePath: "dark/images/rangeslider-first-handle-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-first-handle-hovered"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 17992
+ readonly property real y: 2723
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17148;8624:14400"
+ readonly property string filePath: "dark/images/rangeslider-groove-hovered.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17972
+ readonly property real y: 2731
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17148;8624:14506"
+ readonly property string filePath: "dark/images/rangeslider-second-handle-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-second-handle-hovered"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 18116
+ readonly property real y: 2723
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17148;8624:14402"
+ readonly property string filePath: "dark/images/rangeslider-track-hovered.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 18002
+ readonly property real y: 2731
+ }
+
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17146;2509:12436;2509:12419"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17964
+ readonly property real y: 2665
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17146;2509:12436"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17146;2509:12436;4189:38496"
+ readonly property string filePath: "dark/images/rangeslider-first-handle.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-first-handle"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 17992
+ readonly property real y: 2665
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17146;2509:12436;4178:28261"
+ readonly property string filePath: "dark/images/rangeslider-groove.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17972
+ readonly property real y: 2673
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17146;2509:12436;4191:43003"
+ readonly property string filePath: "dark/images/rangeslider-second-handle.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-second-handle"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 18116
+ readonly property real y: 2665
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17146;2509:12436;4189:38505"
+ readonly property string filePath: "dark/images/rangeslider-track.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 18002
+ readonly property real y: 2673
+ }
+
+ }
+
+ }
+
+ readonly property QtObject slider: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17178;2506:12695;4200:48590"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22952
+ readonly property real y: 2827.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17178;2506:12695"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17178;2506:12695;4385:9106"
+ readonly property string filePath: "dark/images/slider-groove-disabled.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22960
+ readonly property real y: 2835.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17178;2506:12695;4200:48601"
+ readonly property string filePath: "dark/images/slider-handle-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "slider-handle-disabled"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 23123
+ readonly property real y: 2827.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17178;2506:12695;4200:48597"
+ readonly property string filePath: "dark/images/slider-track-disabled.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22960
+ readonly property real y: 2835.5
+ }
+
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17174;8624:13850"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22952
+ readonly property real y: 2708.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17174;8624:13849"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17174;8624:13853"
+ readonly property string filePath: "dark/images/slider-groove-hovered.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22960
+ readonly property real y: 2716.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17174;8624:13874"
+ readonly property string filePath: "dark/images/slider-handle-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "slider-handle-hovered"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 23123
+ readonly property real y: 2708.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17174;8624:13855"
+ readonly property string filePath: "dark/images/slider-track-hovered.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22960
+ readonly property real y: 2716.5
+ }
+
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17172;2506:12656;4200:48590"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22952
+ readonly property real y: 2649.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17172;2506:12656"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17172;2506:12656;4385:9106"
+ readonly property string filePath: "dark/images/slider-groove.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22960
+ readonly property real y: 2657.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17172;2506:12656;4200:48601"
+ readonly property string filePath: "dark/images/slider-handle.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "slider-handle"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 23123
+ readonly property real y: 2649.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17172;2506:12656;4200:48597"
+ readonly property string filePath: "dark/images/slider-track.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22960
+ readonly property real y: 2657.5
+ }
+
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17176;8624:14647"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22952
+ readonly property real y: 2768.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17176;8624:14646"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17176;8624:14650"
+ readonly property string filePath: "dark/images/slider-groove-pressed.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22960
+ readonly property real y: 2776.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17176;8624:14671"
+ readonly property string filePath: "dark/images/slider-handle-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "slider-handle-pressed"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 23123
+ readonly property real y: 2768.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17176;8624:14652"
+ readonly property string filePath: "dark/images/slider-track-pressed.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22960
+ readonly property real y: 2776.5
+ }
+
+ }
+
+ }
+
+ readonly property QtObject switch_: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17204;2531:14856;4350:34538"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2250.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17204;2531:14856"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17204;2531:14856;4350:34543"
+ readonly property string filePath: "dark/images/switch-handle-checked.png"
+ readonly property real height: 12
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 1
+ readonly property string name: "switch-handle-checked"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 6
+ readonly property real topShadow: 1
+ readonly property real width: 12
+ readonly property real x: 25826.5
+ readonly property real y: 2260.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17204;2531:14856;4350:34541"
+ readonly property string filePath: "dark/images/switch-handle-background-checked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2256.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:17204;2531:14856;4350:34542"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-handle-contentItem-checked"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17204;2531:14856;6761:23654"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2256.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17212;2531:14900;4350:34538"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2454.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17212;2531:14900"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked-disabled"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17212;2531:14900;4350:34543"
+ readonly property string filePath: "dark/images/switch-handle-checked-disabled.png"
+ readonly property real height: 12
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 1
+ readonly property string name: "switch-handle-checked-disabled"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 6
+ readonly property real topShadow: 1
+ readonly property real width: 12
+ readonly property real x: 25826.5
+ readonly property real y: 2464.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17212;2531:14900;4350:34541"
+ readonly property string filePath: "dark/images/switch-handle-background-checked-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked-disabled"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2460.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:17212;2531:14900;4350:34542"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-handle-contentItem-checked-disabled"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17212;2531:14900;6761:23654"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2460.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17208;8664:14952"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2352.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17208;8664:14951"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked-hovered"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17208;8664:14975"
+ readonly property string filePath: "dark/images/switch-handle-checked-hovered.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 7
+ readonly property real leftShadow: 1
+ readonly property string name: "switch-handle-checked-hovered"
+ readonly property real rightOffset: 6
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 7
+ readonly property real topShadow: 1
+ readonly property real width: 14
+ readonly property real x: 25825.5
+ readonly property real y: 2361.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17208;8664:14954"
+ readonly property string filePath: "dark/images/switch-handle-background-checked-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked-hovered"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2358.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:17208;8664:14955"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-checked-hovered"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17208;8664:14957"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2358.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17210;8664:14801"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2403.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17210;8664:14800"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked-pressed"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17210;8664:14824"
+ readonly property string filePath: "dark/images/switch-handle-checked-pressed.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 1
+ readonly property string name: "switch-handle-checked-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 7
+ readonly property real topShadow: 1
+ readonly property real width: 17
+ readonly property real x: 25822.5
+ readonly property real y: 2412.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17210;8664:14803"
+ readonly property string filePath: "dark/images/switch-handle-background-checked-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked-pressed"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2409.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:17210;8664:14804"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-checked-pressed"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17210;8664:14806"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2409.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17206;2531:14867;2942:5449"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2301.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17206;2531:14867"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-disabled"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17206;2531:14867;2531:14816"
+ readonly property string filePath: "dark/images/switch-handle-disabled.png"
+ readonly property real height: 12
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-disabled"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 6
+ readonly property real topShadow: 0
+ readonly property real width: 12
+ readonly property real x: 25806.5
+ readonly property real y: 2311.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17206;2531:14867;2531:14819"
+ readonly property string filePath: "dark/images/switch-handle-background-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-disabled"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2307.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:17206;2531:14867;2531:14811"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-handle-contentItem-disabled"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17206;2531:14867;6761:24226"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2307.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17200;8664:14878"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2148.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17200;8664:14877"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-hovered"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17200;8664:14900"
+ readonly property string filePath: "dark/images/switch-handle-hovered.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 7
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-hovered"
+ readonly property real rightOffset: 6
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 7
+ readonly property real topShadow: 0
+ readonly property real width: 14
+ readonly property real x: 25805.5
+ readonly property real y: 2157.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17200;8664:14880"
+ readonly property string filePath: "dark/images/switch-handle-background-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-hovered"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2154.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:17200;8664:14881"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-hovered"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17200;8664:14883"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2154.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17198;2531:14823;2942:5449"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2091.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17198;2531:14823"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17198;2531:14823;2531:14816"
+ readonly property string filePath: "dark/images/switch-handle.png"
+ readonly property real height: 12
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 6
+ readonly property real topShadow: 0
+ readonly property real width: 12
+ readonly property real x: 25806.5
+ readonly property real y: 2101.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17198;2531:14823;2531:14819"
+ readonly property string filePath: "dark/images/switch-handle-background.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2097.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:17198;2531:14823;2531:14811"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-handle-contentItem"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17198;2531:14823;6761:24226"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2097.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17202;8664:14715"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2199.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17202;8664:14714"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-pressed"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17202;8664:14737"
+ readonly property string filePath: "dark/images/switch-handle-pressed.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 7
+ readonly property real topShadow: 0
+ readonly property real width: 17
+ readonly property real x: 25805.5
+ readonly property real y: 2208.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17202;8664:14717"
+ readonly property string filePath: "dark/images/switch-handle-background-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-pressed"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2205.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:17202;8664:14718"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-pressed"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17202;8664:14720"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2205.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ }
+
+ readonly property QtObject textarea: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 3
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17226;2554:13608;2554:13585"
+ readonly property string filePath: "dark/images/textarea-background-disabled.png"
+ readonly property real height: 50
+ readonly property real leftOffset: 3
+ readonly property real leftShadow: 1
+ readonly property string name: "textarea-background-disabled"
+ readonly property real rightOffset: 3
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 3
+ readonly property real topShadow: 1
+ readonly property real width: 200
+ readonly property real x: 30417.5
+ readonly property real y: 2590
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17226;2554:13608"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "textarea-contentItem-disabled"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17226;2554:13608;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30428.5
+ readonly property real y: 2595
+ }
+
+ readonly property real leftPadding: 11
+ readonly property real rightPadding: 11
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject focused: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 3
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2654:6248;2654:5963;2554:13585"
+ readonly property string filePath: "dark/images/textarea-background-focused.png"
+ readonly property real height: 50
+ readonly property real leftOffset: 3
+ readonly property real leftShadow: 1
+ readonly property string name: "textarea-background-focused"
+ readonly property real rightOffset: 3
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 3
+ readonly property real topShadow: 1
+ readonly property real width: 200
+ readonly property real x: 30417.5
+ readonly property real y: 2667
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2654:6248;2654:5963"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "textarea-contentItem-focused"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2654:6248;2654:5963;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label-focused"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30428.5
+ readonly property real y: 2672
+ }
+
+ readonly property real leftPadding: 11
+ readonly property real rightPadding: 11
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 3
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17224;2554:13603;2554:13585"
+ readonly property string filePath: "dark/images/textarea-background-hovered.png"
+ readonly property real height: 50
+ readonly property real leftOffset: 3
+ readonly property real leftShadow: 1
+ readonly property string name: "textarea-background-hovered"
+ readonly property real rightOffset: 3
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 3
+ readonly property real topShadow: 1
+ readonly property real width: 200
+ readonly property real x: 30417.5
+ readonly property real y: 2513
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17224;2554:13603"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "textarea-contentItem-hovered"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17224;2554:13603;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30428.5
+ readonly property real y: 2518
+ }
+
+ readonly property real leftPadding: 11
+ readonly property real rightPadding: 11
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 3
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17222;2554:13588;2554:13585"
+ readonly property string filePath: "dark/images/textarea-background.png"
+ readonly property real height: 50
+ readonly property real leftOffset: 3
+ readonly property real leftShadow: 1
+ readonly property string name: "textarea-background"
+ readonly property real rightOffset: 3
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 3
+ readonly property real topShadow: 1
+ readonly property real width: 200
+ readonly property real x: 30417.5
+ readonly property real y: 2436
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17222;2554:13588"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "textarea-contentItem"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17222;2554:13588;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30428.5
+ readonly property real y: 2441
+ }
+
+ readonly property real leftPadding: 11
+ readonly property real rightPadding: 11
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject textfield: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17219;2537:15922;2537:15894"
+ readonly property string filePath: "dark/images/textfield-background-disabled.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 1
+ readonly property string name: "textfield-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 4
+ readonly property real topShadow: 1
+ readonly property real width: 158
+ readonly property real x: 29552
+ readonly property real y: 1873.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17219;2537:15922"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17219;2537:15922;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29564
+ readonly property real y: 1878.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject focused: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2644:5979;2644:5955;2537:15894"
+ readonly property string filePath: "dark/images/textfield-background-focused.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 1
+ readonly property string name: "textfield-background-focused"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 4
+ readonly property real topShadow: 1
+ readonly property real width: 158
+ readonly property real x: 29552
+ readonly property real y: 1942.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2644:5979;2644:5955"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem-focused"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2644:5979;2644:5955;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label-focused"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29564
+ readonly property real y: 1947.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17217;2537:15917;2537:15894"
+ readonly property string filePath: "dark/images/textfield-background-hovered.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 1
+ readonly property string name: "textfield-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 4
+ readonly property real topShadow: 1
+ readonly property real width: 158
+ readonly property real x: 29552
+ readonly property real y: 1804.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17217;2537:15917"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17217;2537:15917;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29564
+ readonly property real y: 1809.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17215;2537:15912;2537:15894"
+ readonly property string filePath: "dark/images/textfield-background.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 1
+ readonly property string name: "textfield-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 4
+ readonly property real topShadow: 1
+ readonly property real width: 158
+ readonly property real x: 29552
+ readonly property real y: 1735.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17215;2537:15912"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17215;2537:15912;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29564
+ readonly property real y: 1740.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ }
+ }
+ readonly property QtObject light: QtObject {
+ readonly property QtObject controls: QtObject {
+ readonly property QtObject button: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15399;2356:10516;2373:10903"
+ readonly property string filePath: "light/images/button-background-checked.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2467
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15399;2356:10516"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15399;2356:10516;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2474
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15399;2356:10516;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2472
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15405;2356:10522;2373:10903"
+ readonly property string filePath: "light/images/button-background-checked-disabled.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2668
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15405;2356:10522"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15405;2356:10522;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2675
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15405;2356:10522;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2673
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15403;2356:10520;2373:10903"
+ readonly property string filePath: "light/images/button-background-checked-hovered.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2601
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15403;2356:10520"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15403;2356:10520;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2608
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15403;2356:10520;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2606
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15407;2356:10524;2373:10903"
+ readonly property string filePath: "light/images/button-background-checked-pressed.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2735
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15407;2356:10524"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15407;2356:10524;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2742
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15407;2356:10524;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2740
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15401;2356:10518;2373:10903"
+ readonly property string filePath: "light/images/button-background-disabled.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2534
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15401;2356:10518"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15401;2356:10518;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2541
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15401;2356:10518;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2539
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15395;2356:10512;2373:10903"
+ readonly property string filePath: "light/images/button-background-hovered.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2333
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15395;2356:10512"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15395;2356:10512;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2340
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15395;2356:10512;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2338
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15393;2356:10510;2373:10903"
+ readonly property string filePath: "light/images/button-background.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2227.5
+ readonly property real y: 2278
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15393;2356:10510"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15393;2356:10510;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2247.5
+ readonly property real y: 2285
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15393;2356:10510;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2271.5
+ readonly property real y: 2283
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15397;2356:10514;2373:10903"
+ readonly property string filePath: "light/images/button-background-pressed.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2400
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15397;2356:10514"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15397;2356:10514;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2407
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15397;2356:10514;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2405
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject checkbox: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15416;2829:5675;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 1941.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15416;2829:5675"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15416;2829:5675;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-checked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 1947.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15416;2829:5675;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 1947.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15426;2427:12224;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2217.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15426;2427:12224"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15426;2427:12224;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-checked-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2223.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15426;2427:12224;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2223.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15430;2829:5737;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2079.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15430;2829:5737"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15430;2829:5737;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-checked-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2085.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15430;2829:5737;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2085.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15428;2425:12191;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2148.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15428;2425:12191"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15428;2425:12191;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-checked-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2154.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15428;2425:12191;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2154.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15432;2829:5710;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2010.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15432;2829:5710"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15432;2829:5710;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2016.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15432;2829:5710;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2016.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject disabled_partiallyChecked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15424;2427:12263;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-disabled-partiallyChecked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2493.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15424;2427:12263"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-disabled-partiallyChecked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15424;2427:12263;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-disabled-partiallyChecked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-disabled-partiallyChecked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2499.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15424;2427:12263;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-disabled-partiallyChecked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2499.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15412;2829:5612;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 1803.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15412;2829:5612"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15412;2829:5612;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 1809.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15412;2829:5612;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 1809.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered_partiallyChecked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15420;2427:12244;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-hovered-partiallyChecked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2355.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15420;2427:12244"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-hovered-partiallyChecked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15420;2427:12244;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-hovered-partiallyChecked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-hovered-partiallyChecked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2361.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15420;2427:12244;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-hovered-partiallyChecked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2361.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15410;2829:5455;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 1734.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15410;2829:5455"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15410;2829:5455;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 1740.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15410;2829:5455;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 1740.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject partiallyChecked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15418;2427:12233;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-partiallyChecked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2286.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15418;2427:12233"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-partiallyChecked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15418;2427:12233;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-partiallyChecked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-partiallyChecked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2292.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15418;2427:12233;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-partiallyChecked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2292.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject partiallyChecked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15422;2427:12254;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-partiallyChecked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2424.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15422;2427:12254"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-partiallyChecked-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15422;2427:12254;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-partiallyChecked-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-partiallyChecked-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2430.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15422;2427:12254;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-partiallyChecked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2430.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15414;2829:5648;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 1872.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15414;2829:5648"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15414;2829:5648;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 1878.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15414;2829:5648;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 1878.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ }
+
+ readonly property QtObject flatbutton: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9165;3987:9104;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-checked.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 2040.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9165;3987:9104"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9165;3987:9104;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 2045.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9165;3987:9104;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 2045.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9168;3987:9122;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-checked-disabled.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked-disabled"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 2174.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9168;3987:9122"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9168;3987:9122;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 2179.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9168;3987:9122;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 2179.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9167;3987:9113;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-checked-hovered.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked-hovered"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 2107.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9167;3987:9113"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9167;3987:9113;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 2112.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9167;3987:9113;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 2112.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9169;3987:9131;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-checked-pressed.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked-pressed"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 2241.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9169;3987:9131"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9169;3987:9131;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 2246.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9169;3987:9131;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 2246.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9166;3987:9095;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-disabled.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-disabled"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 1973.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9166;3987:9095"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9166;3987:9095;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 1978.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9166;3987:9095;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 1978.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9163;3987:9077;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-hovered.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-hovered"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 1839.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9163;3987:9077"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9163;3987:9077;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 1844.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9163;3987:9077;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 1844.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9162;3987:9068;3987:9044"
+ readonly property string filePath: ""
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 1772.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9162;3987:9068"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9162;3987:9068;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 1777.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9162;3987:9068;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 1777.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9164;3987:9086;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-pressed.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-pressed"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 15
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 1906.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9164;3987:9086"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9164;3987:9086;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 1911.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9164;3987:9086;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 1911.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject progressbar: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9316;4304:9328"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem-disabled"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9316;4304:9328;4413:23724"
+ readonly property string filePath: "light/images/progressbar-groove-disabled.png"
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15598
+ readonly property real y: 2059
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9316;4304:9328;4267:14564"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15598
+ readonly property real y: 2058
+ }
+
+ }
+
+ readonly property QtObject disabled_indeterminate: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9318;4304:9355"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem-disabled-indeterminate"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9318;4304:9355;4350:35746"
+ readonly property string filePath: ""
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove-disabled-indeterminate"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15598
+ readonly property real y: 2132
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9318;4304:9355;4403:22724"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track-disabled-indeterminate"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15664
+ readonly property real y: 2131
+ }
+
+ }
+
+ readonly property QtObject indeterminate: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9317;2450:12847"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem-indeterminate"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9317;2450:12847;4350:35746"
+ readonly property string filePath: ""
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove-indeterminate"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15598
+ readonly property real y: 1986
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9317;2450:12847;4403:22724"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track-indeterminate"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15664
+ readonly property real y: 1985
+ }
+
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9315;2450:12841"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9315;2450:12841;4413:23724"
+ readonly property string filePath: "light/images/progressbar-groove.png"
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15598
+ readonly property real y: 1913
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9315;2450:12841;4267:14564"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15598
+ readonly property real y: 1912
+ }
+
+ }
+
+ }
+
+ readonly property QtObject radiobutton: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15511;2483:15472;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 1977.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15511;2483:15472"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15511;2483:15472;2473:12871"
+ readonly property string filePath: "light/images/radiobutton-indicator-checked.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 1983.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15511;2483:15472;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 1985.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15517;2488:15512;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 2255.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15517;2488:15512"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15517;2488:15512;2473:12871"
+ readonly property string filePath: "light/images/radiobutton-indicator-checked-disabled.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 2261.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15517;2488:15512;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 2263.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15513;8622:14986"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 2119.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15513;8622:14985"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15513;8622:14996"
+ readonly property string filePath: "light/images/radiobutton-indicator-checked-hovered.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 2125.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15513;8622:14988"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 2127.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15515;8622:15023"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 2186.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15515;8622:15022"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15515;8622:15033"
+ readonly property string filePath: "light/images/radiobutton-indicator-checked-pressed.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 2192.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15515;8622:15025"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 2194.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15519;2483:15480;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 2048.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15519;2483:15480"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15519;2483:15480;2473:12871"
+ readonly property string filePath: "light/images/radiobutton-indicator-disabled.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 2054.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15519;2483:15480;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 2056.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15507;2473:12899;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 1839.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15507;2473:12899"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15507;2473:12899;2473:12871"
+ readonly property string filePath: "light/images/radiobutton-indicator-hovered.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 1845.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15507;2473:12899;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 1847.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15505;2473:12891;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 1770.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15505;2473:12891"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15505;2473:12891;2473:12871"
+ readonly property string filePath: "light/images/radiobutton-indicator.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 1776.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15505;2473:12891;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 1778.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15509;8622:15060"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 1908.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15509;8622:15059"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15509;8622:15070"
+ readonly property string filePath: "light/images/radiobutton-indicator-pressed.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 1914.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15509;8622:15062"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 1916.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ }
+
+ readonly property QtObject rangeslider: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15528;2509:12481;2509:12419"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17634
+ readonly property real y: 2839
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15528;2509:12481"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15528;2509:12481;4189:38496"
+ readonly property string filePath: "light/images/rangeslider-first-handle-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-first-handle-disabled"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 17662
+ readonly property real y: 2839
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15528;2509:12481;4178:28261"
+ readonly property string filePath: "light/images/rangeslider-groove-disabled.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17642
+ readonly property real y: 2847
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15528;2509:12481;4191:43003"
+ readonly property string filePath: "light/images/rangeslider-second-handle-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-second-handle-disabled"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 17786
+ readonly property real y: 2839
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15528;2509:12481;4189:38505"
+ readonly property string filePath: "light/images/rangeslider-track-disabled.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 17672
+ readonly property real y: 2847
+ }
+
+ }
+
+ readonly property QtObject handle_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15526;8624:14526"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background-handle-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17634
+ readonly property real y: 2781
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15526;8624:14525"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem-handle-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15526;8624:14556"
+ readonly property string filePath: "light/images/rangeslider-first-handle-handle-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-first-handle-handle-pressed"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 17662
+ readonly property real y: 2781
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15526;8624:14529"
+ readonly property string filePath: "light/images/rangeslider-groove-handle-pressed.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove-handle-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17642
+ readonly property real y: 2789
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15526;8624:14627"
+ readonly property string filePath: "light/images/rangeslider-second-handle-handle-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-second-handle-handle-pressed"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 17786
+ readonly property real y: 2781
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15526;8624:14531"
+ readonly property string filePath: "light/images/rangeslider-track-handle-pressed.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track-handle-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 17672
+ readonly property real y: 2789
+ }
+
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15524;8624:14397"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17634
+ readonly property real y: 2723
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15524;8624:14396"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15524;8624:14427"
+ readonly property string filePath: "light/images/rangeslider-first-handle-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-first-handle-hovered"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 17662
+ readonly property real y: 2723
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15524;8624:14400"
+ readonly property string filePath: "light/images/rangeslider-groove-hovered.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17642
+ readonly property real y: 2731
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15524;8624:14506"
+ readonly property string filePath: "light/images/rangeslider-second-handle-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-second-handle-hovered"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 17786
+ readonly property real y: 2723
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15524;8624:14402"
+ readonly property string filePath: "light/images/rangeslider-track-hovered.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 17672
+ readonly property real y: 2731
+ }
+
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15522;2509:12436;2509:12419"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17634
+ readonly property real y: 2665
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15522;2509:12436"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15522;2509:12436;4189:38496"
+ readonly property string filePath: "light/images/rangeslider-first-handle.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-first-handle"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 17662
+ readonly property real y: 2665
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15522;2509:12436;4178:28261"
+ readonly property string filePath: "light/images/rangeslider-groove.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17642
+ readonly property real y: 2673
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15522;2509:12436;4191:43003"
+ readonly property string filePath: "light/images/rangeslider-second-handle.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "rangeslider-second-handle"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 17786
+ readonly property real y: 2665
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15522;2509:12436;4189:38505"
+ readonly property string filePath: "light/images/rangeslider-track.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 17672
+ readonly property real y: 2673
+ }
+
+ }
+
+ }
+
+ readonly property QtObject slider: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15554;2506:12695;4200:48590"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22622
+ readonly property real y: 2827.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15554;2506:12695"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15554;2506:12695;4385:9106"
+ readonly property string filePath: "light/images/slider-groove-disabled.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22630
+ readonly property real y: 2835.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15554;2506:12695;4200:48601"
+ readonly property string filePath: "light/images/slider-handle-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "slider-handle-disabled"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 22793
+ readonly property real y: 2827.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15554;2506:12695;4200:48597"
+ readonly property string filePath: "light/images/slider-track-disabled.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22630
+ readonly property real y: 2835.5
+ }
+
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15550;8624:13850"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22622
+ readonly property real y: 2708.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15550;8624:13849"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15550;8624:13853"
+ readonly property string filePath: "light/images/slider-groove-hovered.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22630
+ readonly property real y: 2716.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15550;8624:13874"
+ readonly property string filePath: "light/images/slider-handle-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "slider-handle-hovered"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 22793
+ readonly property real y: 2708.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15550;8624:13855"
+ readonly property string filePath: "light/images/slider-track-hovered.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22630
+ readonly property real y: 2716.5
+ }
+
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15548;2506:12656;4200:48590"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22622
+ readonly property real y: 2649.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15548;2506:12656"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15548;2506:12656;4385:9106"
+ readonly property string filePath: "light/images/slider-groove.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22630
+ readonly property real y: 2657.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15548;2506:12656;4200:48601"
+ readonly property string filePath: "light/images/slider-handle.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "slider-handle"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 22793
+ readonly property real y: 2649.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15548;2506:12656;4200:48597"
+ readonly property string filePath: "light/images/slider-track.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22630
+ readonly property real y: 2657.5
+ }
+
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15552;8624:14647"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22622
+ readonly property real y: 2768.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15552;8624:14646"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15552;8624:14650"
+ readonly property string filePath: "light/images/slider-groove-pressed.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22630
+ readonly property real y: 2776.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15552;8624:14671"
+ readonly property string filePath: "light/images/slider-handle-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 1
+ readonly property string name: "slider-handle-pressed"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 10
+ readonly property real topShadow: 1
+ readonly property real width: 20
+ readonly property real x: 22793
+ readonly property real y: 2768.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15552;8624:14652"
+ readonly property string filePath: "light/images/slider-track-pressed.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22630
+ readonly property real y: 2776.5
+ }
+
+ }
+
+ }
+
+ readonly property QtObject switch_: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15580;2531:14856;4350:34538"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2250.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15580;2531:14856"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15580;2531:14856;4350:34543"
+ readonly property string filePath: "light/images/switch-handle-checked.png"
+ readonly property real height: 12
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 1
+ readonly property string name: "switch-handle-checked"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 6
+ readonly property real topShadow: 1
+ readonly property real width: 12
+ readonly property real x: 25646.5
+ readonly property real y: 2260.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15580;2531:14856;4350:34541"
+ readonly property string filePath: "light/images/switch-handle-background-checked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2256.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:15580;2531:14856;4350:34542"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-handle-contentItem-checked"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15580;2531:14856;6761:23654"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2256.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15588;2531:14900;4350:34538"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2454.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15588;2531:14900"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked-disabled"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15588;2531:14900;4350:34543"
+ readonly property string filePath: "light/images/switch-handle-checked-disabled.png"
+ readonly property real height: 12
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 1
+ readonly property string name: "switch-handle-checked-disabled"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 6
+ readonly property real topShadow: 1
+ readonly property real width: 12
+ readonly property real x: 25646.5
+ readonly property real y: 2464.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15588;2531:14900;4350:34541"
+ readonly property string filePath: "light/images/switch-handle-background-checked-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked-disabled"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2460.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:15588;2531:14900;4350:34542"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-handle-contentItem-checked-disabled"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15588;2531:14900;6761:23654"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2460.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15584;8664:14952"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2352.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15584;8664:14951"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked-hovered"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15584;8664:14975"
+ readonly property string filePath: "light/images/switch-handle-checked-hovered.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 7
+ readonly property real leftShadow: 1
+ readonly property string name: "switch-handle-checked-hovered"
+ readonly property real rightOffset: 6
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 7
+ readonly property real topShadow: 1
+ readonly property real width: 14
+ readonly property real x: 25645.5
+ readonly property real y: 2361.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15584;8664:14954"
+ readonly property string filePath: "light/images/switch-handle-background-checked-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked-hovered"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2358.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:15584;8664:14955"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-checked-hovered"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15584;8664:14957"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2358.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15586;8664:14801"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2403.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15586;8664:14800"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked-pressed"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15586;8664:14824"
+ readonly property string filePath: "light/images/switch-handle-checked-pressed.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 1
+ readonly property string name: "switch-handle-checked-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 7
+ readonly property real topShadow: 1
+ readonly property real width: 17
+ readonly property real x: 25642.5
+ readonly property real y: 2412.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15586;8664:14803"
+ readonly property string filePath: "light/images/switch-handle-background-checked-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked-pressed"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2409.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:15586;8664:14804"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-checked-pressed"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15586;8664:14806"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2409.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15582;2531:14867;2942:5449"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2301.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15582;2531:14867"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-disabled"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15582;2531:14867;2531:14816"
+ readonly property string filePath: "light/images/switch-handle-disabled.png"
+ readonly property real height: 12
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-disabled"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 6
+ readonly property real topShadow: 0
+ readonly property real width: 12
+ readonly property real x: 25626.5
+ readonly property real y: 2311.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15582;2531:14867;2531:14819"
+ readonly property string filePath: "light/images/switch-handle-background-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-disabled"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2307.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:15582;2531:14867;2531:14811"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-handle-contentItem-disabled"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15582;2531:14867;6761:24226"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2307.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15576;8664:14878"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2148.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15576;8664:14877"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-hovered"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15576;8664:14900"
+ readonly property string filePath: "light/images/switch-handle-hovered.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 7
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-hovered"
+ readonly property real rightOffset: 6
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 7
+ readonly property real topShadow: 0
+ readonly property real width: 14
+ readonly property real x: 25625.5
+ readonly property real y: 2157.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15576;8664:14880"
+ readonly property string filePath: "light/images/switch-handle-background-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-hovered"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2154.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:15576;8664:14881"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-hovered"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15576;8664:14883"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2154.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15574;2531:14823;2942:5449"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2091.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15574;2531:14823"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15574;2531:14823;2531:14816"
+ readonly property string filePath: "light/images/switch-handle.png"
+ readonly property real height: 12
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 6
+ readonly property real topShadow: 0
+ readonly property real width: 12
+ readonly property real x: 25626.5
+ readonly property real y: 2101.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15574;2531:14823;2531:14819"
+ readonly property string filePath: "light/images/switch-handle-background.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2097.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:15574;2531:14823;2531:14811"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-handle-contentItem"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15574;2531:14823;6761:24226"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2097.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15578;8664:14715"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2199.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15578;8664:14714"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-pressed"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15578;8664:14737"
+ readonly property string filePath: "light/images/switch-handle-pressed.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 7
+ readonly property real topShadow: 0
+ readonly property real width: 17
+ readonly property real x: 25625.5
+ readonly property real y: 2208.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15578;8664:14717"
+ readonly property string filePath: "light/images/switch-handle-background-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-pressed"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2205.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:15578;8664:14718"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-pressed"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15578;8664:14720"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2205.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ }
+
+ readonly property QtObject textarea: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 3
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15602;2554:13608;2554:13585"
+ readonly property string filePath: "light/images/textarea-background-disabled.png"
+ readonly property real height: 50
+ readonly property real leftOffset: 3
+ readonly property real leftShadow: 1
+ readonly property string name: "textarea-background-disabled"
+ readonly property real rightOffset: 3
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 3
+ readonly property real topShadow: 1
+ readonly property real width: 200
+ readonly property real x: 30156
+ readonly property real y: 2590
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15602;2554:13608"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "textarea-contentItem-disabled"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15602;2554:13608;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30167
+ readonly property real y: 2595
+ }
+
+ readonly property real leftPadding: 11
+ readonly property real rightPadding: 11
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject focused: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 3
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2654:6236;2654:5963;2554:13585"
+ readonly property string filePath: "light/images/textarea-background-focused.png"
+ readonly property real height: 50
+ readonly property real leftOffset: 3
+ readonly property real leftShadow: 1
+ readonly property string name: "textarea-background-focused"
+ readonly property real rightOffset: 3
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 3
+ readonly property real topShadow: 1
+ readonly property real width: 200
+ readonly property real x: 30156
+ readonly property real y: 2667
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2654:6236;2654:5963"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "textarea-contentItem-focused"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2654:6236;2654:5963;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label-focused"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30167
+ readonly property real y: 2672
+ }
+
+ readonly property real leftPadding: 11
+ readonly property real rightPadding: 11
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 3
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15600;2554:13603;2554:13585"
+ readonly property string filePath: "light/images/textarea-background-hovered.png"
+ readonly property real height: 50
+ readonly property real leftOffset: 3
+ readonly property real leftShadow: 1
+ readonly property string name: "textarea-background-hovered"
+ readonly property real rightOffset: 3
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 3
+ readonly property real topShadow: 1
+ readonly property real width: 200
+ readonly property real x: 30156
+ readonly property real y: 2513
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15600;2554:13603"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "textarea-contentItem-hovered"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15600;2554:13603;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30167
+ readonly property real y: 2518
+ }
+
+ readonly property real leftPadding: 11
+ readonly property real rightPadding: 11
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 3
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15598;2554:13588;2554:13585"
+ readonly property string filePath: "light/images/textarea-background.png"
+ readonly property real height: 50
+ readonly property real leftOffset: 3
+ readonly property real leftShadow: 1
+ readonly property string name: "textarea-background"
+ readonly property real rightOffset: 3
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 3
+ readonly property real topShadow: 1
+ readonly property real width: 200
+ readonly property real x: 30156
+ readonly property real y: 2436
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15598;2554:13588"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "textarea-contentItem"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15598;2554:13588;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30167
+ readonly property real y: 2441
+ }
+
+ readonly property real leftPadding: 11
+ readonly property real rightPadding: 11
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject textfield: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15595;2537:15922;2537:15894"
+ readonly property string filePath: "light/images/textfield-background-disabled.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 1
+ readonly property string name: "textfield-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 4
+ readonly property real topShadow: 1
+ readonly property real width: 158
+ readonly property real x: 29362
+ readonly property real y: 1873.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15595;2537:15922"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15595;2537:15922;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29374
+ readonly property real y: 1878.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject focused: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2644:5967;2644:5955;2537:15894"
+ readonly property string filePath: "light/images/textfield-background-focused.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 1
+ readonly property string name: "textfield-background-focused"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 4
+ readonly property real topShadow: 1
+ readonly property real width: 158
+ readonly property real x: 29362
+ readonly property real y: 1942.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2644:5967;2644:5955"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem-focused"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2644:5967;2644:5955;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label-focused"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29374
+ readonly property real y: 1947.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15593;2537:15917;2537:15894"
+ readonly property string filePath: "light/images/textfield-background-hovered.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 1
+ readonly property string name: "textfield-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 4
+ readonly property real topShadow: 1
+ readonly property real width: 158
+ readonly property real x: 29362
+ readonly property real y: 1804.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15593;2537:15917"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15593;2537:15917;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29374
+ readonly property real y: 1809.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 1
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15591;2537:15912;2537:15894"
+ readonly property string filePath: "light/images/textfield-background.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 1
+ readonly property string name: "textfield-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 1
+ readonly property real topOffset: 4
+ readonly property real topShadow: 1
+ readonly property real width: 158
+ readonly property real x: 29362
+ readonly property real y: 1735.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15591;2537:15912"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15591;2537:15912;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29374
+ readonly property real y: 1740.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/ProgressBar.qml b/src/quickcontrols/fluentwinui3/ProgressBar.qml
new file mode 100644
index 0000000000..513f624e04
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/ProgressBar.qml
@@ -0,0 +1,117 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.Effects
+
+T.ProgressBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: [
+ !control.enabled && "disabled",
+ control.indeterminate && "indeterminate"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.progressbar[__currentState] || {}
+
+ contentItem: Item {
+ implicitWidth: control.indeterminate ? parent.availableWidth : progress.implicitWidth
+ implicitHeight: control.indeterminate ? control.config.track.height : progress.implicitHeight
+ scale: control.mirrored ? -1 : 1
+ clip: control.indeterminate
+
+ readonly property Rectangle progress: Rectangle {
+ x: control.background.groove?.x - 1
+ y: control.background.groove?.y - 1
+ parent: control.contentItem
+ visible: !control.indeterminate && control.value
+ implicitWidth: control.config.track.width
+ implicitHeight: control.config.track.height
+ width: control.position * parent.width
+ height: control.config.track.height
+ radius: control.config.track.height * 0.5
+ color: control.palette.accent
+ }
+
+ readonly property Rectangle animatedProgress: Rectangle {
+ parent: control.contentItem
+ implicitWidth: parent.width
+ implicitHeight: control.config.track.height
+ radius: control.config.track.height * 0.5
+ clip: true
+ visible: false
+ color: "transparent"
+ Rectangle {
+ width: 0.5 * parent.width
+ height: control.config.track.height
+ radius: control.config.track.height * 0.5
+ color: control.palette.accent
+ SequentialAnimation on x {
+ loops: Animation.Infinite
+ running: control.indeterminate && control.visible
+ NumberAnimation {
+ from: -control.contentItem.animatedProgress.width
+ to: control.contentItem.width
+ easing.type: Easing.InOutCubic
+ duration: control.width * 8
+ }
+ NumberAnimation {
+ from: -control.contentItem.animatedProgress.width * 0.5
+ to: control.contentItem.width
+ easing.type: Easing.InOutCubic
+ duration: control.width * 5
+ }
+ }
+ }
+ }
+
+ readonly property Rectangle mask: Rectangle {
+ parent: control.contentItem
+ width: control.availableWidth
+ height: control.contentItem.animatedProgress.height
+ radius: control.contentItem.animatedProgress.radius
+ visible: false
+ color: control.palette.accent
+ layer.enabled: true
+ antialiasing: false
+ }
+
+ MultiEffect {
+ visible: control.indeterminate
+ source: control.contentItem.animatedProgress
+ width: control.contentItem.animatedProgress.width
+ height: control.contentItem.animatedProgress.height
+ maskEnabled: true
+ maskSource: control.contentItem.mask
+ }
+ }
+
+ background: Item {
+ implicitWidth: groove.width
+ property Item groove: StyleImage {
+ imageConfig: control.config.groove
+ visible: !control.indeterminate
+ parent: control.background
+ height: implicitHeight
+ width: parent.width
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/RadioButton.qml b/src/quickcontrols/fluentwinui3/RadioButton.qml
new file mode 100644
index 0000000000..ee1ed8d4ad
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/RadioButton.qml
@@ -0,0 +1,59 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.RadioButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: config.spacing || 0
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: [
+ control.checked && "checked",
+ !control.enabled && "disabled",
+ control.enabled && !control.down && control.hovered && "hovered",
+ control.down && "pressed"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.radiobutton[__currentState] || {}
+ readonly property bool mirroredIndicator: control.mirrored !== (config.mirrored || false)
+
+ indicator: Image {
+ x: control.text ? (control.mirroredIndicator ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ source: Qt.resolvedUrl(control.config.indicator.filePath)
+ }
+
+ contentItem: Text {
+ leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0
+ rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0
+
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/RangeSlider.qml b/src/quickcontrols/fluentwinui3/RangeSlider.qml
new file mode 100644
index 0000000000..7cf5c2c81f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/RangeSlider.qml
@@ -0,0 +1,197 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.RangeSlider {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ first.implicitHandleWidth + leftPadding + rightPadding,
+ second.implicitHandleWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ first.implicitHandleHeight + topPadding + bottomPadding,
+ second.implicitHandleHeight + topPadding + bottomPadding)
+
+ topPadding: horizontal ? config.topPadding : config.leftPadding || 0
+ leftPadding: horizontal ? config.leftPadding : config.bottomPadding || 0
+ rightPadding: horizontal ? config.rightPadding : config.topPadding || 0
+ bottomPadding: horizontal ? config.bottomPadding : config.rightPadding || 0
+
+ readonly property string __controlState: [
+ !control.enabled && "disabled",
+ control.enabled && control.hovered && !(first.pressed || second.pressed) && "hovered",
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.rangeslider[__controlState] || {}
+
+ readonly property real __steps: Math.abs(to - from) / stepSize
+ readonly property bool __isDiscrete: stepSize >= Number.EPSILON
+ && Math.abs(Math.round(__steps) - __steps) < Number.EPSILON
+
+ property string __firstHandleState: [
+ !control.enabled && "disabled",
+ first.hovered && !first.pressed && "hovered",
+ first.pressed && "handle_pressed",
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var firstHandleConfig: Config.controls.rangeslider[__firstHandleState] || {}
+
+ property string __secondHandleState: [
+ !control.enabled && "disabled",
+ second.hovered && !second.pressed && "hovered",
+ second.pressed && "handle_pressed",
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var secondHandleConfig: Config.controls.rangeslider[__secondHandleState] || {}
+
+ first.handle: StyleImage {
+ x: Math.round(control.leftPadding + (control.horizontal
+ ? control.first.visualPosition * (control.availableWidth - width)
+ : (control.availableWidth - width) / 2))
+ y: Math.round(control.topPadding + (control.horizontal
+ ? (control.availableHeight - height) / 2
+ : control.first.visualPosition * (control.availableHeight - height)))
+
+ imageConfig: control.firstHandleConfig.first_handle
+
+ property Rectangle indicator: Rectangle {
+ property real diameter: control.first.pressed ? 8 : control.first.hovered ? 14 : 10
+ parent: control.first.handle
+ width: diameter
+ height: diameter
+ radius: diameter * 0.5
+ x: (control.secondHandleConfig.first_handle.width - width) / 2
+ y: (control.secondHandleConfig.first_handle.height - height) / 2
+ color: control.first.pressed
+ ? Qt.styleHints.colorScheme == Qt.Light ? "#CC005FB8" : "#CC60CDFF"// AccentFillColorTertiary
+ : control.palette.accent
+ Behavior on diameter {
+ // From WindowsUI 3 Animation Values
+ NumberAnimation{
+ duration: 167
+ easing.type: Easing.OutCubic
+ }
+ }
+ }
+ }
+
+ second.handle: StyleImage {
+ x: Math.round(control.leftPadding + (control.horizontal
+ ? control.second.visualPosition * (control.availableWidth - width)
+ : (control.availableWidth - width) / 2))
+ y: Math.round(control.topPadding + (control.horizontal
+ ? (control.availableHeight - height) / 2
+ : control.second.visualPosition * (control.availableHeight - height)))
+
+ imageConfig: control.secondHandleConfig.second_handle
+
+ property Rectangle indicator: Rectangle {
+ property real diameter: control.second.pressed ? 8 : control.second.hovered ? 14 : 10
+ parent: control.second.handle
+ width: diameter
+ height: diameter
+ radius: diameter * 0.5
+ x: (control.secondHandleConfig.second_handle.width - width) / 2
+ y: (control.secondHandleConfig.second_handle.height - height) / 2
+ color: control.second.pressed
+ ? Qt.styleHints.colorScheme == Qt.Light ? "#CC005FB8" : "#CC60CDFF"// AccentFillColorTertiary
+ : control.palette.accent
+ Behavior on diameter {
+ // From WindowsUI 3 Animation Values
+ NumberAnimation{
+ duration: 167
+ easing.type: Easing.OutCubic
+ }
+ }
+ }
+ }
+
+ background: Item {
+ implicitWidth: control.horizontal
+ ? (_background.implicitWidth || _background.groove.implicitWidth)
+ : (_background.implicitHeight || _background.groove.implicitHeight)
+ implicitHeight: control.horizontal
+ ? (_background.implicitHeight || _background.groove.implicitHeight)
+ : (_background.implicitWidth || _background.groove.implicitWidth)
+
+ property Item _background: StyleImage {
+ parent: control.background
+ width: parent.width
+ height: parent.width
+ imageConfig: control.config.background
+
+ property Item groove: StyleImage {
+ parent: control.background._background
+ x: control.leftPadding - control.leftInset + (control.horizontal
+ ? control.firstHandleConfig.first_handle.width / 2
+ : (control.availableWidth - width) / 2)
+ y: control.topPadding - control.rightInset + (control.horizontal
+ ? ((control.availableHeight - height) / 2)
+ : control.firstHandleConfig.first_handle.height / 2)
+
+ width: control.horizontal
+ ? control.availableWidth
+ - (control.firstHandleConfig.first_handle.width / 2) - (control.secondHandleConfig.second_handle.width / 2)
+ : implicitWidth
+ height: control.horizontal
+ ? implicitHeight
+ : control.availableHeight
+ - (control.firstHandleConfig.first_handle.width / 2) - (control.secondHandleConfig.second_handle.width / 2)
+ imageConfig: control.config.groove
+ horizontal: control.horizontal
+
+ property Item track: StyleImage {
+ parent: control.background._background.groove
+ x: horizontal ? parent.width * control.first.position : 0
+ y: horizontal ? 0 : parent.height - (parent.height * control.second.position)
+ width: horizontal
+ ? parent.width * (control.second.position - control.first.position)
+ : parent.width
+ height: horizontal
+ ? parent.height
+ : parent.height * (control.second.position - control.first.position)
+ imageConfig: control.config.track
+ horizontal: control.horizontal
+ minimumWidth: 0
+ minimumHeight: 0
+ }
+ }
+
+ property Repeater ticksTop: Repeater {
+ parent: control.background._background.groove
+ model: control.__isDiscrete ? Math.floor(control.__steps) + 1 : 0
+ delegate: Rectangle {
+ width: control.horizontal ? 1 : 4
+ height: control.horizontal ? 4 : 1
+ x: control.horizontal
+ ? 6 + index * (parent.width - 2 * 6 - width) / (control.background._background.ticksTop.model - 1)
+ : -4 - width
+ y: control.horizontal
+ ? -4 - height
+ : 6 + index * (parent.height - 2 * 6 - height) / (control.background._background.ticksTop.model - 1)
+ color: Qt.styleHints.colorScheme == Qt.Light ? "#9C000000" : "#9AFFFFFF"
+
+ required property int index
+ }
+ }
+
+ property Repeater ticksBottom: Repeater {
+ parent: control.background._background.groove
+ model: control.__isDiscrete ? Math.floor(control.__steps) + 1 : 0
+ delegate: Rectangle {
+ width: control.horizontal ? 1 : 4
+ height: control.horizontal ? 4 : 1
+ x: control.horizontal
+ ? 6 + index * (parent.width - 2 * 6 - width) / (control.background._background.ticksBottom.model - 1)
+ : parent.width + 4
+ y: control.horizontal
+ ? parent.height + 4
+ : 6 + index * (parent.height - 2 * 6 - height) / (control.background._background.ticksBottom.model - 1)
+ color: Qt.styleHints.colorScheme == Qt.Light ? "#9C000000" : "#9AFFFFFF"
+
+ required property int index
+ }
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/Slider.qml b/src/quickcontrols/fluentwinui3/Slider.qml
new file mode 100644
index 0000000000..e5fb871f1c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/Slider.qml
@@ -0,0 +1,144 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Slider {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitHandleWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitHandleHeight + topPadding + bottomPadding)
+
+ topPadding: horizontal ? config.topPadding : config.leftPadding || 0
+ leftPadding: horizontal ? config.leftPadding : config.bottomPadding || 0
+ rightPadding: horizontal ? config.rightPadding : config.topPadding || 0
+ bottomPadding: horizontal ? config.bottomPadding : config.rightPadding || 0
+
+ readonly property string __currentState: [
+ !control.enabled && "disabled",
+ control.enabled && !control.pressed && control.hovered && "hovered",
+ control.pressed && "pressed"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.slider[__currentState] || {}
+
+ readonly property real __steps: Math.abs(to - from) / stepSize
+ readonly property bool __isDiscrete: stepSize >= Number.EPSILON
+ && Math.abs(Math.round(__steps) - __steps) < Number.EPSILON
+
+ handle: StyleImage {
+ x: Math.round(control.leftPadding + (control.horizontal
+ ? control.visualPosition * (control.availableWidth - width)
+ : (control.availableWidth - width) / 2))
+ y: Math.round(control.topPadding + (control.horizontal
+ ? (control.availableHeight - height) / 2
+ : control.visualPosition * (control.availableHeight - height)))
+
+ imageConfig: control.config.handle
+
+ property Rectangle indicator: Rectangle {
+ property real diameter: control.pressed ? 8 : control.hovered ? 14 : 10
+ parent: control.handle
+ width: diameter
+ height: diameter
+ radius: diameter * 0.5
+ x: (control.config.handle.width - width) / 2
+ y: (control.config.handle.height - height) / 2
+ color: control.pressed
+ ? Qt.styleHints.colorScheme == Qt.Light ? "#CC005FB8" : "#CC60CDFF"// AccentFillColorTertiary
+ : control.palette.accent
+ Behavior on diameter {
+ // From WindowsUI 3 Animation Values
+ NumberAnimation{
+ duration: 167
+ easing.type: Easing.OutCubic
+ }
+ }
+ }
+ }
+
+ background: Item {
+ implicitWidth: control.horizontal
+ ? (_background.implicitWidth || _background.groove.implicitWidth)
+ : (_background.implicitHeight || _background.groove.implicitHeight)
+ implicitHeight: control.horizontal
+ ? (_background.implicitHeight || _background.groove.implicitHeight)
+ : (_background.implicitWidth || _background.groove.implicitWidth)
+
+ property Item _background: StyleImage {
+ parent: control.background
+ width: parent.width
+ height: parent.height
+ imageConfig: control.config.background
+
+ property Item groove: StyleImage {
+ parent: control.background._background
+ x: control.leftPadding - control.leftInset + (control.horizontal
+ ? control.config.handle.width / 2
+ : (control.availableWidth - width) / 2)
+ y: control.topPadding - control.topInset + (control.horizontal
+ ? ((control.availableHeight - height) / 2)
+ : control.config.handle.height / 2)
+
+ width: control.horizontal
+ ? control.availableWidth - control.config.handle.width
+ : implicitWidth
+ height: control.horizontal
+ ? implicitHeight
+ : control.availableHeight - control.config.handle.width
+ imageConfig: control.config.groove
+ horizontal: control.horizontal
+
+ property Item track: StyleImage {
+ parent: control.background._background.groove
+ y: horizontal ? 0 : parent.height - (parent.height * control.position)
+ width: horizontal ? parent.width * control.position : parent.width
+ height: horizontal ? parent.height : parent.height * control.position
+ imageConfig: control.config.track
+ horizontal: control.horizontal
+ minimumWidth: 0
+ minimumHeight: 0
+ }
+ }
+
+ property Repeater ticksTop: Repeater {
+ parent: control.background._background.groove
+ model: control.__isDiscrete ? Math.floor(control.__steps) + 1 : 0
+ delegate: Rectangle {
+ width: control.horizontal ? 1 : 4
+ height: control.horizontal ? 4 : 1
+ x: control.horizontal
+ ? 6 + index * (parent.width - 2 * 6 - width) / (control.background._background.ticksTop.model - 1)
+ : -4 - width
+ y: control.horizontal
+ ? -4 - height
+ : 6 + index * (parent.height - 2 * 6 - height) / (control.background._background.ticksTop.model - 1)
+ color: Qt.styleHints.colorScheme == Qt.Light ? "#9C000000" : "#9AFFFFFF"
+
+ required property int index
+ }
+ }
+
+ property Repeater ticksBottom: Repeater {
+ parent: control.background._background.groove
+ model: control.__isDiscrete ? Math.floor(control.__steps) + 1 : 0
+ delegate: Rectangle {
+ width: control.horizontal ? 1 : 4
+ height: control.horizontal ? 4 : 1
+ x: control.horizontal
+ ? 6 + index * (parent.width - 2 * 6 - width) / (control.background._background.ticksBottom.model - 1)
+ : parent.width + 4
+ y: control.horizontal
+ ? parent.height + 4
+ : 6 + index * (parent.height - 2 * 6 - height) / (control.background._background.ticksBottom.model - 1)
+ color: Qt.styleHints.colorScheme == Qt.Light ? "#9C000000" : "#9AFFFFFF"
+
+ required property int index
+ }
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/StyleImage.qml b/src/quickcontrols/fluentwinui3/StyleImage.qml
new file mode 100644
index 0000000000..f67b52268b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/StyleImage.qml
@@ -0,0 +1,54 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+
+// This item will resize the child image in such a way that any drop shadow
+// or blur (or other effects) will be drawn outside its own bounds.
+// The effect is that users of this item won't have to take e.g shadows
+// into account when positioning it, as such effects will only be visual, and
+// not be a part of the geometry.
+
+Item {
+ id: root
+ implicitWidth: horizontal ? imageConfig.width : imageConfig.height
+ implicitHeight: horizontal ? imageConfig.height : imageConfig.width
+
+ required property var imageConfig
+
+ // Set horizontal to false if you want the image to be rotated 90 degrees
+ // Doing so will rotate the image, but also flip it, to make sure that
+ // the shadow ends up on the correct side. The implicit geometry of the
+ // item will also be adjusted to match the rotated image.
+ property bool horizontal: true
+
+ // The minimum size of the image should be at least 1px tall and wide, even without any offsets
+ property real minimumWidth: Math.max(1, imageConfig.leftOffset + imageConfig.rightOffset)
+ property real minimumHeight: Math.max(1, imageConfig.topOffset + imageConfig.bottomOffset)
+
+ BorderImage {
+ x: -imageConfig.leftShadow
+ y: -imageConfig.topShadow
+ width: Math.max(root.minimumWidth, (root.horizontal ? root.width : root.height))
+ + imageConfig.leftShadow + imageConfig.rightShadow
+ height: Math.max(root.minimumHeight, (root.horizontal ? root.height : root.width))
+ + imageConfig.topShadow + imageConfig.bottomShadow
+ source: Qt.resolvedUrl(imageConfig.filePath)
+
+ border {
+ top: Math.min(height / 2, imageConfig.topOffset + imageConfig.topShadow)
+ left: Math.min(width / 2, imageConfig.leftOffset + imageConfig.leftShadow)
+ bottom: Math.min(height / 2, imageConfig.bottomOffset + imageConfig.bottomShadow)
+ right: Math.min(width / 2, imageConfig.rightOffset + imageConfig.rightShadow)
+ }
+
+ transform: [
+ Rotation {
+ angle: root.horizontal ? 0 : 90
+ },
+ Scale {
+ xScale: root.horizontal ? 1 : -1
+ }
+ ]
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/Switch.qml b/src/quickcontrols/fluentwinui3/Switch.qml
new file mode 100644
index 0000000000..7821af4d85
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/Switch.qml
@@ -0,0 +1,81 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Switch {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding,
+ implicitIndicatorWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: config.spacing || 0
+
+ topPadding: control.text ? config.topPadding || 0 : 0
+ leftPadding: control.text ? config.leftPadding || 0 : 0
+ rightPadding: control.text ? config.rightPadding || 0 : 0
+ bottomPadding: control.text ? config.bottomPadding || 0 : 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: [
+ control.checked && "checked",
+ !control.enabled && "disabled",
+ control.enabled && !control.down && control.hovered && "hovered",
+ control.down && "pressed"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.switch_[__currentState] || {}
+ readonly property bool mirroredIndicator: control.mirrored !== (config.mirrored || false)
+
+ indicator: Item {
+ x: control.text ? (control.mirroredIndicator ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ // If handleBackground is not generated, use the size of the handle
+ implicitWidth: handleBackground.width > 0 ? handleBackground.width : handleBackground.handle.width * 2
+ implicitHeight: handleBackground.height > 0 ? handleBackground.height : handleBackground.handle.height
+
+ property Item handleBackground: StyleImage {
+ parent: control.indicator
+ imageConfig: control.config.handle_background
+
+ property Item handle: StyleImage {
+ parent: control.indicator.handleBackground
+ x: control.config.handle_contentItem.leftPadding
+ + (control.visualPosition * (parent.width - width
+ - control.config.handle_contentItem.leftPadding
+ - control.config.handle_contentItem.rightPadding))
+ y: control.config.handle_contentItem.topPadding
+
+ imageConfig: control.config.handle
+
+ Behavior on x {
+ enabled: !control.down
+ SmoothedAnimation {
+ velocity: 200
+ }
+ }
+ }
+ }
+ }
+
+ contentItem: Text {
+ leftPadding: control.indicator && !control.mirroredIndicator ? control.indicator.width + control.spacing : 0
+ rightPadding: control.indicator && control.mirroredIndicator ? control.indicator.width + control.spacing : 0
+
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/TextArea.qml b/src/quickcontrols/fluentwinui3/TextArea.qml
new file mode 100644
index 0000000000..88bc8ed32e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/TextArea.qml
@@ -0,0 +1,73 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.FluentWinUI3.impl
+
+T.TextArea {
+ id: control
+
+ implicitWidth: implicitBackgroundWidth + leftInset + rightInset
+ || Math.max(contentWidth, placeholder.implicitWidth) + leftPadding + rightPadding
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding,
+ placeholder.implicitHeight + topPadding + bottomPadding)
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ placeholderTextColor: control.palette.placeholderText
+ verticalAlignment: Text.AlignVCenter
+
+ readonly property string __currentState: [
+ !enabled && "disabled",
+ activeFocus && "focused",
+ enabled && !activeFocus && hovered && "hovered",
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.textarea[__currentState] || {}
+
+ PlaceholderText {
+ id: placeholder
+ x: control.leftPadding
+ y: control.topPadding
+ width: control.width - (control.leftPadding + control.rightPadding)
+ height: control.height - (control.topPadding + control.bottomPadding)
+
+ text: control.placeholderText
+ font: control.font
+ color: control.placeholderTextColor
+ verticalAlignment: control.verticalAlignment
+ horizontalAlignment: control.horizontalAlignment
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ Item{
+ visible: control.activeFocus
+ width: parent.width
+ height: 2
+ y: parent.height
+ FocusStroke {
+ width: parent.width
+ height: parent.height
+ radius: control.config.background.bottomOffset
+ color: control.palette.accent
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/TextField.qml b/src/quickcontrols/fluentwinui3/TextField.qml
new file mode 100644
index 0000000000..faf3e5c653
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/TextField.qml
@@ -0,0 +1,73 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.FluentWinUI3.impl
+
+T.TextField {
+ id: control
+
+ implicitWidth: implicitBackgroundWidth + leftInset + rightInset
+ || Math.max(contentWidth, placeholder.implicitWidth) + leftPadding + rightPadding
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding,
+ placeholder.implicitHeight + topPadding + bottomPadding)
+
+ readonly property string __currentState: [
+ !enabled && "disabled",
+ activeFocus && "focused",
+ enabled && !activeFocus && hovered && "hovered",
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.textfield[__currentState] || {}
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ placeholderTextColor: control.palette.placeholderText
+ verticalAlignment: Text.AlignVCenter
+
+ PlaceholderText {
+ id: placeholder
+ x: control.leftPadding
+ y: control.topPadding
+ width: control.width - (control.leftPadding + control.rightPadding)
+ height: control.height - (control.topPadding + control.bottomPadding)
+
+ text: control.placeholderText
+ font: control.font
+ color: control.placeholderTextColor
+ verticalAlignment: control.verticalAlignment
+ horizontalAlignment: control.horizontalAlignment
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ Item{
+ visible: control.activeFocus
+ width: parent.width
+ height: 2
+ y: parent.height
+ FocusStroke {
+ width: parent.width
+ height: parent.height
+ radius: control.config.background.bottomOffset
+ color: control.palette.accent
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled.png
new file mode 100644
index 0000000000..bb92034cc4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..daddfc06b2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..9bb0bc54f1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered.png
new file mode 100644
index 0000000000..383d9ddad1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..1a63a6cbed
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..a41eca1c90
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed.png
new file mode 100644
index 0000000000..1fab295493
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..8ac083df82
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..a6bc5a55b8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked.png
new file mode 100644
index 0000000000..6ae607c2f5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked@2x.png
new file mode 100644
index 0000000000..220a11b710
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked@3x.png
new file mode 100644
index 0000000000..71cc59b7b8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled.png
new file mode 100644
index 0000000000..536999ca06
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@2x.png
new file mode 100644
index 0000000000..e1164d037a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@3x.png
new file mode 100644
index 0000000000..4d8b06e9fa
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered.png
new file mode 100644
index 0000000000..9ddabae7bf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@2x.png
new file mode 100644
index 0000000000..60200ccd66
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@3x.png
new file mode 100644
index 0000000000..006d94ff06
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed.png
new file mode 100644
index 0000000000..747a15bbbd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@2x.png
new file mode 100644
index 0000000000..d2f5d53d2b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@3x.png
new file mode 100644
index 0000000000..f6826f7bbe
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background.png b/src/quickcontrols/fluentwinui3/dark/images/button-background.png
new file mode 100644
index 0000000000..f680342164
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background@2x.png
new file mode 100644
index 0000000000..25f3037f75
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background@3x.png
new file mode 100644
index 0000000000..418a4ad8d9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled.png
new file mode 100644
index 0000000000..51875ef456
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@2x.png
new file mode 100644
index 0000000000..da6c369391
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@3x.png
new file mode 100644
index 0000000000..3237492196
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered.png
new file mode 100644
index 0000000000..782b2a68de
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..0dc5055479
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..139335118f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed.png
new file mode 100644
index 0000000000..76970066ee
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..0509f4d664
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..556455107a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked.png
new file mode 100644
index 0000000000..403a1e1024
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@2x.png
new file mode 100644
index 0000000000..4de05c6ae5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@3x.png
new file mode 100644
index 0000000000..b15eb6cad9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked.png
new file mode 100644
index 0000000000..dbe1078410
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@2x.png
new file mode 100644
index 0000000000..f2b8f27295
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@3x.png
new file mode 100644
index 0000000000..9ce7c8694c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled.png
new file mode 100644
index 0000000000..9ddaed9b31
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@2x.png
new file mode 100644
index 0000000000..3da6cc9855
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@3x.png
new file mode 100644
index 0000000000..a4dd2cc4bd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked.png
new file mode 100644
index 0000000000..e68c8c955b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@2x.png
new file mode 100644
index 0000000000..78428a678f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@3x.png
new file mode 100644
index 0000000000..a794fe8d22
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered.png
new file mode 100644
index 0000000000..5c57f70d33
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@2x.png
new file mode 100644
index 0000000000..7ec3a4c89b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@3x.png
new file mode 100644
index 0000000000..e135f3c80c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed.png
new file mode 100644
index 0000000000..c3fc742a7e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@2x.png
new file mode 100644
index 0000000000..d7d53072fd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@3x.png
new file mode 100644
index 0000000000..5c7de6da3b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked.png
new file mode 100644
index 0000000000..9f17c19e0f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@2x.png
new file mode 100644
index 0000000000..8c0aa879d3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@3x.png
new file mode 100644
index 0000000000..f35230ff18
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed.png
new file mode 100644
index 0000000000..9d6772b4cc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@2x.png
new file mode 100644
index 0000000000..8028f68b45
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@3x.png
new file mode 100644
index 0000000000..19ed4c69c0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator.png
new file mode 100644
index 0000000000..f51009e79c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@2x.png
new file mode 100644
index 0000000000..c63e5b63b8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@3x.png
new file mode 100644
index 0000000000..573d31cba9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled.png
new file mode 100644
index 0000000000..7117388f0c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..30883b48b6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..04408607f4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered.png
new file mode 100644
index 0000000000..c1e7a46e70
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..be9a80ffc2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..3de62048f5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed.png
new file mode 100644
index 0000000000..39994fef41
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..71c20c92b5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..477ab7cfa5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked.png
new file mode 100644
index 0000000000..d328d7d66b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@2x.png
new file mode 100644
index 0000000000..04ddbda7dd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@3x.png
new file mode 100644
index 0000000000..3f4e1b6c2a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled.png
new file mode 100644
index 0000000000..a4d7c618e4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@2x.png
new file mode 100644
index 0000000000..409b795bbf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@3x.png
new file mode 100644
index 0000000000..74c089c6cc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered.png
new file mode 100644
index 0000000000..adf332a327
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@2x.png
new file mode 100644
index 0000000000..fa2533a520
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@3x.png
new file mode 100644
index 0000000000..d29ba95d84
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed.png
new file mode 100644
index 0000000000..94587941c8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@2x.png
new file mode 100644
index 0000000000..948b253d85
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@3x.png
new file mode 100644
index 0000000000..a79ef1b740
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled-indeterminate.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled-indeterminate.png
new file mode 100644
index 0000000000..c4a8916446
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled-indeterminate.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled-indeterminate@2x.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled-indeterminate@2x.png
new file mode 100644
index 0000000000..31cde58066
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled-indeterminate@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled-indeterminate@3x.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled-indeterminate@3x.png
new file mode 100644
index 0000000000..cc1aa71758
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled-indeterminate@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled.png
new file mode 100644
index 0000000000..c4a8916446
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@2x.png
new file mode 100644
index 0000000000..31cde58066
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@3x.png
new file mode 100644
index 0000000000..cc1aa71758
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-indeterminate.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-indeterminate.png
new file mode 100644
index 0000000000..c7ba3d6a64
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-indeterminate.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-indeterminate@2x.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-indeterminate@2x.png
new file mode 100644
index 0000000000..d2134559a2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-indeterminate@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-indeterminate@3x.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-indeterminate@3x.png
new file mode 100644
index 0000000000..5be9cff56e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-indeterminate@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove.png
new file mode 100644
index 0000000000..c7ba3d6a64
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@2x.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@2x.png
new file mode 100644
index 0000000000..d2134559a2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@3x.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@3x.png
new file mode 100644
index 0000000000..5be9cff56e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled.png
new file mode 100644
index 0000000000..bede00df2e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@2x.png
new file mode 100644
index 0000000000..48e0d653f7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@3x.png
new file mode 100644
index 0000000000..f4197aefa6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered.png
new file mode 100644
index 0000000000..c7a80d1950
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..1d967f62c8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..ce18b4dd48
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed.png
new file mode 100644
index 0000000000..8214ae0382
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..5b5f3c6dd1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..42e3779ae2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked.png
new file mode 100644
index 0000000000..905524743c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@2x.png
new file mode 100644
index 0000000000..e5ec6207bb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@3x.png
new file mode 100644
index 0000000000..df43c37131
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled.png
new file mode 100644
index 0000000000..81664eebee
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@2x.png
new file mode 100644
index 0000000000..24432b453d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@3x.png
new file mode 100644
index 0000000000..e2d77d49d7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered.png
new file mode 100644
index 0000000000..d41c1269b0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@2x.png
new file mode 100644
index 0000000000..38713114ce
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@3x.png
new file mode 100644
index 0000000000..d1a2b95f57
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed.png
new file mode 100644
index 0000000000..5a3b5dc669
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@2x.png
new file mode 100644
index 0000000000..b264c4bc8e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@3x.png
new file mode 100644
index 0000000000..8f5984d5ba
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator.png
new file mode 100644
index 0000000000..0ee4bdd3bc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@2x.png
new file mode 100644
index 0000000000..ecaf91b2b7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@3x.png
new file mode 100644
index 0000000000..cf12731708
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled.png
new file mode 100644
index 0000000000..61063b3c1d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@2x.png
new file mode 100644
index 0000000000..67b4b314be
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@3x.png
new file mode 100644
index 0000000000..a0503f6f09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed.png
new file mode 100644
index 0000000000..61063b3c1d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@2x.png
new file mode 100644
index 0000000000..67b4b314be
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@3x.png
new file mode 100644
index 0000000000..a0503f6f09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered.png
new file mode 100644
index 0000000000..cf5f72f106
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@2x.png
new file mode 100644
index 0000000000..247d3d870c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@3x.png
new file mode 100644
index 0000000000..325e21e9c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle.png
new file mode 100644
index 0000000000..cf5f72f106
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@2x.png
new file mode 100644
index 0000000000..247d3d870c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@3x.png
new file mode 100644
index 0000000000..325e21e9c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled.png
new file mode 100644
index 0000000000..045b2ec08b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@2x.png
new file mode 100644
index 0000000000..6916b75992
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@3x.png
new file mode 100644
index 0000000000..e867a49937
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed.png
new file mode 100644
index 0000000000..d0d1b5700f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@2x.png
new file mode 100644
index 0000000000..6c3a04a15c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@3x.png
new file mode 100644
index 0000000000..5d69d4b991
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered.png
new file mode 100644
index 0000000000..d0d1b5700f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@2x.png
new file mode 100644
index 0000000000..6c3a04a15c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@3x.png
new file mode 100644
index 0000000000..5d69d4b991
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove.png
new file mode 100644
index 0000000000..d0d1b5700f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@2x.png
new file mode 100644
index 0000000000..6c3a04a15c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@3x.png
new file mode 100644
index 0000000000..5d69d4b991
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled.png
new file mode 100644
index 0000000000..61063b3c1d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@2x.png
new file mode 100644
index 0000000000..67b4b314be
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@3x.png
new file mode 100644
index 0000000000..a0503f6f09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed.png
new file mode 100644
index 0000000000..61063b3c1d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@2x.png
new file mode 100644
index 0000000000..67b4b314be
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@3x.png
new file mode 100644
index 0000000000..a0503f6f09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered.png
new file mode 100644
index 0000000000..cf5f72f106
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@2x.png
new file mode 100644
index 0000000000..247d3d870c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@3x.png
new file mode 100644
index 0000000000..325e21e9c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle.png
new file mode 100644
index 0000000000..cf5f72f106
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@2x.png
new file mode 100644
index 0000000000..247d3d870c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@3x.png
new file mode 100644
index 0000000000..325e21e9c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-disabled.png
new file mode 100644
index 0000000000..ef00c765fe
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-disabled@2x.png
new file mode 100644
index 0000000000..21b3f8de22
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-disabled@3x.png
new file mode 100644
index 0000000000..c73a5965a5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-handle-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-handle-pressed.png
new file mode 100644
index 0000000000..ffdd620e76
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-handle-pressed@2x.png
new file mode 100644
index 0000000000..b079db0464
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-handle-pressed@3x.png
new file mode 100644
index 0000000000..08a6bed937
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-hovered.png
new file mode 100644
index 0000000000..46d11a30f6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-hovered@2x.png
new file mode 100644
index 0000000000..529993b4de
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-hovered@3x.png
new file mode 100644
index 0000000000..81b854f096
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track.png
new file mode 100644
index 0000000000..46d11a30f6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track@2x.png
new file mode 100644
index 0000000000..529993b4de
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track@3x.png
new file mode 100644
index 0000000000..81b854f096
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-track@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled.png
new file mode 100644
index 0000000000..3160859956
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@2x.png
new file mode 100644
index 0000000000..a680350fdd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@3x.png
new file mode 100644
index 0000000000..000dcfc999
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered.png
new file mode 100644
index 0000000000..8e011e1abb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@2x.png
new file mode 100644
index 0000000000..636896f973
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@3x.png
new file mode 100644
index 0000000000..bcc655e1ac
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed.png
new file mode 100644
index 0000000000..8e011e1abb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@2x.png
new file mode 100644
index 0000000000..636896f973
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@3x.png
new file mode 100644
index 0000000000..bcc655e1ac
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove.png
new file mode 100644
index 0000000000..8e011e1abb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove@2x.png
new file mode 100644
index 0000000000..636896f973
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove@3x.png
new file mode 100644
index 0000000000..bcc655e1ac
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled.png
new file mode 100644
index 0000000000..61063b3c1d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@2x.png
new file mode 100644
index 0000000000..67b4b314be
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@3x.png
new file mode 100644
index 0000000000..a0503f6f09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered.png
new file mode 100644
index 0000000000..cf5f72f106
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@2x.png
new file mode 100644
index 0000000000..247d3d870c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@3x.png
new file mode 100644
index 0000000000..325e21e9c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed.png
new file mode 100644
index 0000000000..61063b3c1d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@2x.png
new file mode 100644
index 0000000000..67b4b314be
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@3x.png
new file mode 100644
index 0000000000..a0503f6f09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle.png
new file mode 100644
index 0000000000..cf5f72f106
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle@2x.png
new file mode 100644
index 0000000000..247d3d870c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle@3x.png
new file mode 100644
index 0000000000..325e21e9c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-track-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/slider-track-disabled.png
new file mode 100644
index 0000000000..6f41f6e5f4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-track-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-track-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-track-disabled@2x.png
new file mode 100644
index 0000000000..cb26c30ddf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-track-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-track-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-track-disabled@3x.png
new file mode 100644
index 0000000000..071137a739
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-track-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-track-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/slider-track-hovered.png
new file mode 100644
index 0000000000..bbac89e6dd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-track-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-track-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-track-hovered@2x.png
new file mode 100644
index 0000000000..c3490b4891
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-track-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-track-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-track-hovered@3x.png
new file mode 100644
index 0000000000..9906e8bd9a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-track-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-track-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/slider-track-pressed.png
new file mode 100644
index 0000000000..835842190d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-track-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-track-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-track-pressed@2x.png
new file mode 100644
index 0000000000..c927fea065
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-track-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-track-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-track-pressed@3x.png
new file mode 100644
index 0000000000..5282bbf9f8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-track-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-track.png b/src/quickcontrols/fluentwinui3/dark/images/slider-track.png
new file mode 100644
index 0000000000..bbac89e6dd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-track.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-track@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-track@2x.png
new file mode 100644
index 0000000000..c3490b4891
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-track@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-track@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-track@3x.png
new file mode 100644
index 0000000000..9906e8bd9a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-track@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled.png
new file mode 100644
index 0000000000..3847e54311
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..36d7cd2d14
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..492feeff72
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered.png
new file mode 100644
index 0000000000..520af09580
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..0d14c010e6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..babf0ed2d4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed.png
new file mode 100644
index 0000000000..9017264f63
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..c91b75f41e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..e1360f4963
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked.png
new file mode 100644
index 0000000000..4e22fd08fe
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@2x.png
new file mode 100644
index 0000000000..94d05aba49
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@3x.png
new file mode 100644
index 0000000000..33a6b39ab5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled.png
new file mode 100644
index 0000000000..67bcb723d3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@2x.png
new file mode 100644
index 0000000000..659e00542e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@3x.png
new file mode 100644
index 0000000000..8f7aa12f03
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered.png
new file mode 100644
index 0000000000..49eaaf2e4e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@2x.png
new file mode 100644
index 0000000000..c0cce54cff
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@3x.png
new file mode 100644
index 0000000000..be9bd9c0de
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed.png
new file mode 100644
index 0000000000..75130db41a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@2x.png
new file mode 100644
index 0000000000..ec72adf408
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@3x.png
new file mode 100644
index 0000000000..721859b8c3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background.png
new file mode 100644
index 0000000000..6d750ef23f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@2x.png
new file mode 100644
index 0000000000..0b0fe38c41
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@3x.png
new file mode 100644
index 0000000000..25032770dd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled.png
new file mode 100644
index 0000000000..81c7e996cd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@2x.png
new file mode 100644
index 0000000000..392a6f8f5a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@3x.png
new file mode 100644
index 0000000000..f422cabeb0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered.png
new file mode 100644
index 0000000000..dcf678415a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@2x.png
new file mode 100644
index 0000000000..54e5aeeea6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@3x.png
new file mode 100644
index 0000000000..02ddaa912d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed.png
new file mode 100644
index 0000000000..3effc502d8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@2x.png
new file mode 100644
index 0000000000..c6cd3ad522
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@3x.png
new file mode 100644
index 0000000000..e139b9e24a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked.png
new file mode 100644
index 0000000000..a4fd9a986d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@2x.png
new file mode 100644
index 0000000000..62c12162f2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@3x.png
new file mode 100644
index 0000000000..aff32fb2c4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled.png
new file mode 100644
index 0000000000..9ff180bec0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@2x.png
new file mode 100644
index 0000000000..4ebfdd2572
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@3x.png
new file mode 100644
index 0000000000..7019635058
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered.png
new file mode 100644
index 0000000000..3a7acdc5ee
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@2x.png
new file mode 100644
index 0000000000..e454ae78b9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@3x.png
new file mode 100644
index 0000000000..fd403d225b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed.png
new file mode 100644
index 0000000000..e270313ca2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@2x.png
new file mode 100644
index 0000000000..717ac3e6c9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@3x.png
new file mode 100644
index 0000000000..010db03b21
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle.png
new file mode 100644
index 0000000000..c95cdad0ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle@2x.png
new file mode 100644
index 0000000000..236a14b5e1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle@3x.png
new file mode 100644
index 0000000000..a4a8186ce8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled.png
new file mode 100644
index 0000000000..62b2429862
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@2x.png
new file mode 100644
index 0000000000..ede013c7e5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@3x.png
new file mode 100644
index 0000000000..da3c10ca52
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused.png
new file mode 100644
index 0000000000..6ff65a8b2f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@2x.png
new file mode 100644
index 0000000000..52fa05d463
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@3x.png
new file mode 100644
index 0000000000..39874e0a1e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered.png
new file mode 100644
index 0000000000..62b2429862
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@2x.png
new file mode 100644
index 0000000000..ede013c7e5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@3x.png
new file mode 100644
index 0000000000..da3c10ca52
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background.png
new file mode 100644
index 0000000000..62b2429862
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background@2x.png
new file mode 100644
index 0000000000..ede013c7e5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background@3x.png
new file mode 100644
index 0000000000..da3c10ca52
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled.png
new file mode 100644
index 0000000000..b7adf0814a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@2x.png
new file mode 100644
index 0000000000..a2a7c2ac2f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@3x.png
new file mode 100644
index 0000000000..7b39a714d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused.png
new file mode 100644
index 0000000000..1ac32dce16
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@2x.png
new file mode 100644
index 0000000000..d65a535a25
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@3x.png
new file mode 100644
index 0000000000..da2a8a9b95
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered.png
new file mode 100644
index 0000000000..1a1904829a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@2x.png
new file mode 100644
index 0000000000..d2463ce4bc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@3x.png
new file mode 100644
index 0000000000..170df46972
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background.png
new file mode 100644
index 0000000000..040752bd4a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background@2x.png
new file mode 100644
index 0000000000..47da0d1297
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background@3x.png
new file mode 100644
index 0000000000..f73f823773
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/impl/CMakeLists.txt b/src/quickcontrols/fluentwinui3/impl/CMakeLists.txt
new file mode 100644
index 0000000000..86657afd34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/impl/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## qtquickcontrols2fluentwinui3styleimplplugin Plugin:
+#####################################################################
+
+qt_internal_add_qml_module(QuickControls2FluentWinUI3StyleImpl
+ URI "QtQuick.Controls.FluentWinUI3.impl"
+ VERSION "${PROJECT_VERSION}"
+ PAST_MAJOR_VERSIONS 2
+ CLASS_NAME QtQuickControls2FluentWinUI3StyleImplPlugin
+ DEPENDENCIES
+ QtQuick/auto
+ PLUGIN_TARGET qtquickcontrols2fluentwinui3styleimplplugin
+ SOURCES
+ qquickfluentwinui3focusstroke_p.h qquickfluentwinui3focusstroke.cpp
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::Qml
+ Qt::QmlPrivate
+ Qt::Quick
+ Qt::QuickPrivate
+)
diff --git a/src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke.cpp b/src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke.cpp
new file mode 100644
index 0000000000..508d614f1c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke.cpp
@@ -0,0 +1,52 @@
+
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qquickfluentwinui3focusstroke_p.h"
+#include <QtGui/qpainter.h>
+#include <QtGui/qpainterpath.h>
+#include <QtQuick/private/qquickitem_p.h>
+QT_BEGIN_NAMESPACE
+QQuickFluentWinUI3FocusStroke::QQuickFluentWinUI3FocusStroke(QQuickItem *parent)
+ : QQuickPaintedItem(parent)
+{
+}
+void QQuickFluentWinUI3FocusStroke::paint(QPainter *painter)
+{
+ painter->setRenderHint(QPainter::Antialiasing);
+ QPainterPath path;
+ QRectF rect = boundingRect();
+ path.moveTo(rect.left(), rect.top() + m_radius);
+ path.lineTo(rect.left(), rect.bottom() - m_radius);
+ path.arcTo(QRectF(rect.left(), rect.bottom() - 2 * m_radius, 2 * m_radius, 2 * m_radius), 180, 90);
+ path.lineTo(rect.right() - m_radius, rect.bottom());
+ path.arcTo(QRectF(rect.right() - 2 * m_radius, rect.bottom() - 2 * m_radius, 2 * m_radius, 2 * m_radius), 270, 90);
+ path.lineTo(rect.right(), rect.top() + m_radius);
+ path.lineTo(rect.right(), rect.top() + m_radius);
+ path.lineTo(rect.right(), rect.top());
+ path.lineTo(rect.left(), rect.top());
+ painter->fillPath(path, m_color);
+}
+QColor QQuickFluentWinUI3FocusStroke::color() const
+{
+ return m_color;
+}
+void QQuickFluentWinUI3FocusStroke::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+ m_color = color;
+ update();
+}
+int QQuickFluentWinUI3FocusStroke::radius() const
+{
+ return m_radius;
+}
+void QQuickFluentWinUI3FocusStroke::setRadius(int radius)
+{
+ if (m_radius == radius)
+ return;
+ m_radius = radius;
+ update();
+}
+QT_END_NAMESPACE
+#include "moc_qquickfluentwinui3focusstroke_p.cpp"
diff --git a/src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke_p.h b/src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke_p.h
new file mode 100644
index 0000000000..1cf9dd1cf6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke_p.h
@@ -0,0 +1,39 @@
+
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QQUICKFLUENTWINUI3FOCUSSTROKE_P_H
+#define QQUICKFLUENTWINUI3FOCUSSTROKE_P_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+#include <QtGui/qcolor.h>
+#include <QtQuick/qquickpainteditem.h>
+#include <QtCore/private/qglobal_p.h>
+QT_BEGIN_NAMESPACE
+class QQuickFluentWinUI3FocusStroke : public QQuickPaintedItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
+ Q_PROPERTY(int radius READ radius WRITE setRadius FINAL)
+ QML_NAMED_ELEMENT(FocusStroke)
+ QML_ADDED_IN_VERSION(6, 8)
+public:
+ explicit QQuickFluentWinUI3FocusStroke(QQuickItem *parent = nullptr);
+ int radius() const;
+ void setRadius(int radius);
+ QColor color() const;
+ void setColor(const QColor &color);
+ void paint(QPainter *painter) override;
+private:
+ QColor m_color = Qt::white;
+ int m_radius;
+};
+QT_END_NAMESPACE
+#endif // QQUICKFLUENTWINUI3FOCUSSTROKE_P_H
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled.png
new file mode 100644
index 0000000000..f68755d41e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..38f6d3817b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..6f9e5d930f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered.png
new file mode 100644
index 0000000000..1252de4261
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..96a2c50191
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..018165e8f9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed.png
new file mode 100644
index 0000000000..6815aa1e9b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..573a5401a6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..44c787cfd5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked.png
new file mode 100644
index 0000000000..879faebba2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked@2x.png
new file mode 100644
index 0000000000..2c547a854c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked@3x.png
new file mode 100644
index 0000000000..cbf7e3c804
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/button-background-disabled.png
new file mode 100644
index 0000000000..d35337835b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-disabled@2x.png
new file mode 100644
index 0000000000..dd775e23f1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-disabled@3x.png
new file mode 100644
index 0000000000..f5a9893edf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/button-background-hovered.png
new file mode 100644
index 0000000000..67ce23bfe4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-hovered@2x.png
new file mode 100644
index 0000000000..541e960331
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-hovered@3x.png
new file mode 100644
index 0000000000..dcf0784da6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-pressed.png b/src/quickcontrols/fluentwinui3/light/images/button-background-pressed.png
new file mode 100644
index 0000000000..d35337835b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-pressed@2x.png
new file mode 100644
index 0000000000..dd775e23f1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-pressed@3x.png
new file mode 100644
index 0000000000..f5a9893edf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background.png b/src/quickcontrols/fluentwinui3/light/images/button-background.png
new file mode 100644
index 0000000000..00de4510db
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background@2x.png
new file mode 100644
index 0000000000..d7c44f598f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background@3x.png
new file mode 100644
index 0000000000..687855e3e7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled.png
new file mode 100644
index 0000000000..63da5de7e5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@2x.png
new file mode 100644
index 0000000000..dfdf16a040
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@3x.png
new file mode 100644
index 0000000000..47cf90c6b2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered.png
new file mode 100644
index 0000000000..eeac692066
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..99f490bc54
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..ac6c762eab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed.png
new file mode 100644
index 0000000000..ae32aa03db
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..e8d64393a1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..d45e246e5b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked.png
new file mode 100644
index 0000000000..457ce21b50
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@2x.png
new file mode 100644
index 0000000000..307d4e1ee7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@3x.png
new file mode 100644
index 0000000000..48d12e1bfa
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked.png
new file mode 100644
index 0000000000..bf72626431
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@2x.png
new file mode 100644
index 0000000000..e98f17b49b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@3x.png
new file mode 100644
index 0000000000..3af1bc8a33
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled.png
new file mode 100644
index 0000000000..99fd3b7b27
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@2x.png
new file mode 100644
index 0000000000..f7bc658b9a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@3x.png
new file mode 100644
index 0000000000..9f2615c189
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked.png
new file mode 100644
index 0000000000..a97fee4277
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@2x.png
new file mode 100644
index 0000000000..5088770c20
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@3x.png
new file mode 100644
index 0000000000..b46bba9417
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered.png
new file mode 100644
index 0000000000..02b068f420
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@2x.png
new file mode 100644
index 0000000000..5ea65d1ebe
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@3x.png
new file mode 100644
index 0000000000..9f51751e12
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed.png
new file mode 100644
index 0000000000..1eb04dc67a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@2x.png
new file mode 100644
index 0000000000..d311e7017a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@3x.png
new file mode 100644
index 0000000000..ce90106703
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked.png
new file mode 100644
index 0000000000..75af72bee0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@2x.png
new file mode 100644
index 0000000000..906cc9c372
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@3x.png
new file mode 100644
index 0000000000..de61118a43
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed.png
new file mode 100644
index 0000000000..d46364bd28
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@2x.png
new file mode 100644
index 0000000000..1fc0fe737d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@3x.png
new file mode 100644
index 0000000000..0a06819118
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator.png
new file mode 100644
index 0000000000..7aeaadc5bd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@2x.png
new file mode 100644
index 0000000000..3bb4cc26eb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@3x.png
new file mode 100644
index 0000000000..801c430a38
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled.png
new file mode 100644
index 0000000000..4c38abadf9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..cb67b46128
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..e88458239a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered.png
new file mode 100644
index 0000000000..70c9c28cba
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..12d4ea853f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..0da8bbf0eb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed.png
new file mode 100644
index 0000000000..e79b356cec
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..f0369ea8fc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..9bca9dde33
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked.png
new file mode 100644
index 0000000000..0307846b61
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@2x.png
new file mode 100644
index 0000000000..d3ab4e1b4b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@3x.png
new file mode 100644
index 0000000000..8a27cd599e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled.png
new file mode 100644
index 0000000000..a4d7c618e4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@2x.png
new file mode 100644
index 0000000000..409b795bbf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@3x.png
new file mode 100644
index 0000000000..74c089c6cc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered.png
new file mode 100644
index 0000000000..60769ff875
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@2x.png
new file mode 100644
index 0000000000..81446127f5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@3x.png
new file mode 100644
index 0000000000..5b2f2d5848
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed.png
new file mode 100644
index 0000000000..8b1c0e17b4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@2x.png
new file mode 100644
index 0000000000..0daa41b34d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@3x.png
new file mode 100644
index 0000000000..f9a1488f9d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled-indeterminate.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled-indeterminate.png
new file mode 100644
index 0000000000..e3e378345c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled-indeterminate.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled-indeterminate@2x.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled-indeterminate@2x.png
new file mode 100644
index 0000000000..dde7433852
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled-indeterminate@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled-indeterminate@3x.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled-indeterminate@3x.png
new file mode 100644
index 0000000000..7cc2351de9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled-indeterminate@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled.png
new file mode 100644
index 0000000000..e3e378345c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@2x.png
new file mode 100644
index 0000000000..dde7433852
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@3x.png
new file mode 100644
index 0000000000..7cc2351de9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-indeterminate.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-indeterminate.png
new file mode 100644
index 0000000000..778a6fa1a0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-indeterminate.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-indeterminate@2x.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-indeterminate@2x.png
new file mode 100644
index 0000000000..bb5bb04b67
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-indeterminate@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-indeterminate@3x.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-indeterminate@3x.png
new file mode 100644
index 0000000000..0c6a055c2f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-indeterminate@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove.png
new file mode 100644
index 0000000000..778a6fa1a0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove@2x.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove@2x.png
new file mode 100644
index 0000000000..bb5bb04b67
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove@3x.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove@3x.png
new file mode 100644
index 0000000000..0c6a055c2f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled.png
new file mode 100644
index 0000000000..d4b4ac2f4c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@2x.png
new file mode 100644
index 0000000000..b14170af18
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@3x.png
new file mode 100644
index 0000000000..6100a1dbdc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered.png
new file mode 100644
index 0000000000..ff087aa284
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..1a84cf450f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..bb32497b9e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed.png
new file mode 100644
index 0000000000..5355792d65
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..102a5afb8d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..e9ec18d655
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked.png
new file mode 100644
index 0000000000..87def1b074
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@2x.png
new file mode 100644
index 0000000000..cb57d16648
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@3x.png
new file mode 100644
index 0000000000..240f7b765b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled.png
new file mode 100644
index 0000000000..96b9b46969
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@2x.png
new file mode 100644
index 0000000000..2d8fcae8c1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@3x.png
new file mode 100644
index 0000000000..c766b07ff5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered.png
new file mode 100644
index 0000000000..12baa9f711
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@2x.png
new file mode 100644
index 0000000000..42922541ec
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@3x.png
new file mode 100644
index 0000000000..7356706576
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed.png
new file mode 100644
index 0000000000..2cb524cb94
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@2x.png
new file mode 100644
index 0000000000..549a661fb2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@3x.png
new file mode 100644
index 0000000000..cdf54c13b0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator.png
new file mode 100644
index 0000000000..ca629420dc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@2x.png
new file mode 100644
index 0000000000..b69426e0bf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@3x.png
new file mode 100644
index 0000000000..84ea625734
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled.png
new file mode 100644
index 0000000000..327fadb2cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@2x.png
new file mode 100644
index 0000000000..a6bf59f43e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@3x.png
new file mode 100644
index 0000000000..0fe63377ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed.png
new file mode 100644
index 0000000000..327fadb2cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@2x.png
new file mode 100644
index 0000000000..a6bf59f43e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@3x.png
new file mode 100644
index 0000000000..0fe63377ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered.png
new file mode 100644
index 0000000000..00d54d428c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@2x.png
new file mode 100644
index 0000000000..a4506f8a34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@3x.png
new file mode 100644
index 0000000000..bd8713f246
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle.png
new file mode 100644
index 0000000000..00d54d428c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@2x.png
new file mode 100644
index 0000000000..a4506f8a34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@3x.png
new file mode 100644
index 0000000000..bd8713f246
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled.png
new file mode 100644
index 0000000000..3b9f471147
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@2x.png
new file mode 100644
index 0000000000..eacadf5052
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@3x.png
new file mode 100644
index 0000000000..e75e6d574c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed.png
new file mode 100644
index 0000000000..2c3d8dd49b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@2x.png
new file mode 100644
index 0000000000..664753e4e3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@3x.png
new file mode 100644
index 0000000000..72acce2411
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered.png
new file mode 100644
index 0000000000..2c3d8dd49b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@2x.png
new file mode 100644
index 0000000000..664753e4e3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@3x.png
new file mode 100644
index 0000000000..72acce2411
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove.png
new file mode 100644
index 0000000000..2c3d8dd49b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@2x.png
new file mode 100644
index 0000000000..664753e4e3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@3x.png
new file mode 100644
index 0000000000..72acce2411
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled.png
new file mode 100644
index 0000000000..327fadb2cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@2x.png
new file mode 100644
index 0000000000..a6bf59f43e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@3x.png
new file mode 100644
index 0000000000..0fe63377ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed.png
new file mode 100644
index 0000000000..327fadb2cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@2x.png
new file mode 100644
index 0000000000..a6bf59f43e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@3x.png
new file mode 100644
index 0000000000..0fe63377ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered.png
new file mode 100644
index 0000000000..00d54d428c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@2x.png
new file mode 100644
index 0000000000..a4506f8a34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@3x.png
new file mode 100644
index 0000000000..bd8713f246
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle.png
new file mode 100644
index 0000000000..00d54d428c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@2x.png
new file mode 100644
index 0000000000..a4506f8a34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@3x.png
new file mode 100644
index 0000000000..bd8713f246
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-disabled.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-disabled.png
new file mode 100644
index 0000000000..0eabbc6f4a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-disabled@2x.png
new file mode 100644
index 0000000000..3622dc1f77
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-disabled@3x.png
new file mode 100644
index 0000000000..829b1ac894
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-handle-pressed.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-handle-pressed.png
new file mode 100644
index 0000000000..9fbfbca9ee
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-handle-pressed@2x.png
new file mode 100644
index 0000000000..f287033e54
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-handle-pressed@3x.png
new file mode 100644
index 0000000000..f11e537a05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-hovered.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-hovered.png
new file mode 100644
index 0000000000..5702858fe7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-hovered@2x.png
new file mode 100644
index 0000000000..c8a86a2c71
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-hovered@3x.png
new file mode 100644
index 0000000000..328e073b17
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-track.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track.png
new file mode 100644
index 0000000000..5702858fe7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-track@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track@2x.png
new file mode 100644
index 0000000000..c8a86a2c71
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-track@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track@3x.png
new file mode 100644
index 0000000000..328e073b17
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-track@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled.png
new file mode 100644
index 0000000000..5d3e751292
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@2x.png
new file mode 100644
index 0000000000..89fb02d418
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@3x.png
new file mode 100644
index 0000000000..425ff1a7c8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered.png
new file mode 100644
index 0000000000..4f6ac3d0b7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@2x.png
new file mode 100644
index 0000000000..4eb9b632af
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@3x.png
new file mode 100644
index 0000000000..3a048d9bbf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed.png
new file mode 100644
index 0000000000..4f6ac3d0b7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@2x.png
new file mode 100644
index 0000000000..4eb9b632af
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@3x.png
new file mode 100644
index 0000000000..3a048d9bbf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove.png
new file mode 100644
index 0000000000..4f6ac3d0b7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove@2x.png
new file mode 100644
index 0000000000..4eb9b632af
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove@3x.png
new file mode 100644
index 0000000000..3a048d9bbf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled.png
new file mode 100644
index 0000000000..327fadb2cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@2x.png
new file mode 100644
index 0000000000..a6bf59f43e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@3x.png
new file mode 100644
index 0000000000..0fe63377ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered.png
new file mode 100644
index 0000000000..00d54d428c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@2x.png
new file mode 100644
index 0000000000..a4506f8a34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@3x.png
new file mode 100644
index 0000000000..bd8713f246
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed.png
new file mode 100644
index 0000000000..327fadb2cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@2x.png
new file mode 100644
index 0000000000..a6bf59f43e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@3x.png
new file mode 100644
index 0000000000..0fe63377ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle.png
new file mode 100644
index 0000000000..00d54d428c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle@2x.png
new file mode 100644
index 0000000000..a4506f8a34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle@3x.png
new file mode 100644
index 0000000000..bd8713f246
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-track-disabled.png b/src/quickcontrols/fluentwinui3/light/images/slider-track-disabled.png
new file mode 100644
index 0000000000..80fb9872ca
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-track-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-track-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-track-disabled@2x.png
new file mode 100644
index 0000000000..c5d12d9635
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-track-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-track-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-track-disabled@3x.png
new file mode 100644
index 0000000000..3b3ab4c737
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-track-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-track-hovered.png b/src/quickcontrols/fluentwinui3/light/images/slider-track-hovered.png
new file mode 100644
index 0000000000..79cb6dd63e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-track-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-track-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-track-hovered@2x.png
new file mode 100644
index 0000000000..bb56c0091a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-track-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-track-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-track-hovered@3x.png
new file mode 100644
index 0000000000..cfdc8db5aa
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-track-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-track-pressed.png b/src/quickcontrols/fluentwinui3/light/images/slider-track-pressed.png
new file mode 100644
index 0000000000..fcae410e3b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-track-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-track-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-track-pressed@2x.png
new file mode 100644
index 0000000000..1eace66002
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-track-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-track-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-track-pressed@3x.png
new file mode 100644
index 0000000000..cf7c4547d5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-track-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-track.png b/src/quickcontrols/fluentwinui3/light/images/slider-track.png
new file mode 100644
index 0000000000..79cb6dd63e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-track.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-track@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-track@2x.png
new file mode 100644
index 0000000000..bb56c0091a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-track@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-track@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-track@3x.png
new file mode 100644
index 0000000000..cfdc8db5aa
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-track@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled.png
new file mode 100644
index 0000000000..e0fff15e93
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..e1be62c482
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..2e7459ec21
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered.png
new file mode 100644
index 0000000000..7809055f68
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..18a5afb7b5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..c09fcb3a06
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed.png
new file mode 100644
index 0000000000..d917aab394
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..ffeeaa73d6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..d1012d151c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked.png
new file mode 100644
index 0000000000..920bae7814
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@2x.png
new file mode 100644
index 0000000000..71b02bf596
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@3x.png
new file mode 100644
index 0000000000..a2a86d0c09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled.png
new file mode 100644
index 0000000000..67bcb723d3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@2x.png
new file mode 100644
index 0000000000..659e00542e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@3x.png
new file mode 100644
index 0000000000..8f7aa12f03
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered.png
new file mode 100644
index 0000000000..c31f0583b6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@2x.png
new file mode 100644
index 0000000000..7f916c1d63
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@3x.png
new file mode 100644
index 0000000000..2b0503fb10
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed.png
new file mode 100644
index 0000000000..3f82932c93
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@2x.png
new file mode 100644
index 0000000000..be4317c0d9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@3x.png
new file mode 100644
index 0000000000..89c76fd903
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background.png
new file mode 100644
index 0000000000..aa5841ef12
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background@2x.png
new file mode 100644
index 0000000000..6802916ceb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background@3x.png
new file mode 100644
index 0000000000..9d3c9ed597
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled.png
new file mode 100644
index 0000000000..507678fb0a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@2x.png
new file mode 100644
index 0000000000..53a97e82f1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@3x.png
new file mode 100644
index 0000000000..2664482c67
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered.png
new file mode 100644
index 0000000000..16dce3eb3a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@2x.png
new file mode 100644
index 0000000000..2b91d9655c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@3x.png
new file mode 100644
index 0000000000..81c046d9cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed.png
new file mode 100644
index 0000000000..5560d91461
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@2x.png
new file mode 100644
index 0000000000..9e4976b90a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@3x.png
new file mode 100644
index 0000000000..387072edf7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked.png
new file mode 100644
index 0000000000..507678fb0a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@2x.png
new file mode 100644
index 0000000000..53a97e82f1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@3x.png
new file mode 100644
index 0000000000..2664482c67
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled.png
new file mode 100644
index 0000000000..334e1d3be6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@2x.png
new file mode 100644
index 0000000000..09ff252d95
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@3x.png
new file mode 100644
index 0000000000..589758481e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered.png
new file mode 100644
index 0000000000..fdb1eb75b8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@2x.png
new file mode 100644
index 0000000000..0271df3682
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@3x.png
new file mode 100644
index 0000000000..f6ab9463a4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed.png
new file mode 100644
index 0000000000..cac0bfc05b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@2x.png
new file mode 100644
index 0000000000..1aaa14a005
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@3x.png
new file mode 100644
index 0000000000..021ae5309b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle.png
new file mode 100644
index 0000000000..c4c16ed8e5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle@2x.png
new file mode 100644
index 0000000000..252db9cecd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle@3x.png
new file mode 100644
index 0000000000..1ebf2fbd5c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled.png
new file mode 100644
index 0000000000..87aa3df215
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@2x.png
new file mode 100644
index 0000000000..ba01f09f71
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@3x.png
new file mode 100644
index 0000000000..efcc5d70ac
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused.png
new file mode 100644
index 0000000000..a83a495d72
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@2x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@2x.png
new file mode 100644
index 0000000000..66547620a9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@3x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@3x.png
new file mode 100644
index 0000000000..fb7967a0d9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered.png
new file mode 100644
index 0000000000..87aa3df215
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@2x.png
new file mode 100644
index 0000000000..ba01f09f71
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@3x.png
new file mode 100644
index 0000000000..efcc5d70ac
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background.png
new file mode 100644
index 0000000000..87aa3df215
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background@2x.png
new file mode 100644
index 0000000000..ba01f09f71
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background@3x.png
new file mode 100644
index 0000000000..efcc5d70ac
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled.png
new file mode 100644
index 0000000000..3c17be5716
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@2x.png
new file mode 100644
index 0000000000..8019ce3f89
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@3x.png
new file mode 100644
index 0000000000..cc4cec589b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused.png
new file mode 100644
index 0000000000..33b7c8ac61
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@2x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@2x.png
new file mode 100644
index 0000000000..10b2cc5ef0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@3x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@3x.png
new file mode 100644
index 0000000000..b523528272
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered.png
new file mode 100644
index 0000000000..7b2be639f8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@2x.png
new file mode 100644
index 0000000000..a6cf97f30a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@3x.png
new file mode 100644
index 0000000000..47f0f0959e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background.png
new file mode 100644
index 0000000000..470b3504a9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background@2x.png
new file mode 100644
index 0000000000..bb330cb081
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background@3x.png
new file mode 100644
index 0000000000..c154d04297
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/qquickfluentwinui3theme.cpp b/src/quickcontrols/fluentwinui3/qquickfluentwinui3theme.cpp
new file mode 100644
index 0000000000..a19393f0ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/qquickfluentwinui3theme.cpp
@@ -0,0 +1,133 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquickfluentwinui3theme_p.h"
+
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qstylehints.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qfontdatabase.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// If on a Windows11 or above, the platform theme will be used to populate the palette
+// We need to fallback to hardcoded colors when using the style on other platforms,
+// that's why we need the following
+// The colors for Windows 11 are taken from the official WinUI3 Figma style at
+// https://www.figma.com/community/file/1159947337437047524
+// Try to keep these consistent with the widget windows11 style
+enum WinUI3Color {
+ solidBackground, // Solid background color used for the bottom most layer
+ textPrimary, // Color for UI labels and static text
+ textSecondary, // Color for text in pressed controls
+ textDisabled, // Color for disabled text
+ textOnAccentPrimary, // Color of text on controls filled in accent color
+ textOnAccentSecondary, // Color of text on sunken controls in accent color
+ textOnAccentDisabled, // Color of text on disabled controls in accent color
+ controlDefault, // Color for standard controls
+ controlDisabled, // Color for disabled controls
+ controlStrokeDefault, // Color for gradient stops in elevations (pressed or disabled state)
+ controlStrokeSecondary, // Color for gradient stops in elevations
+ accentDefault, // Default color for accent fills on controls
+ accentDisabled, // Default color for accent fills on disabled controls
+ accentSecondary, // Color for accent fills on hovered controls
+};
+
+const static QColor WINUI3ColorsLight [] {
+ QColor(0xF3,0xF3,0xF3,0xFF), //solidBackgroundColor
+ QColor(0x00,0x00,0x00,0xE4), //textPrimary
+ QColor(0x00,0x00,0x00,0x9E), //textSecondary
+ QColor(0x00,0x00,0x00,0x5C), //textDisabled
+ QColor(0xFF,0xFF,0xFF,0xFF), //textOnAccentPrimary
+ QColor(0xFF,0xFF,0xFF,0x7F), //textOnAccentSecondary
+ QColor(0xFF,0xFF,0xFF,0xFF), //textOnAccentDisabled
+ QColor(0xFF,0xFF,0xFF,0xB3), //controlDefault
+ QColor(0xF9,0xF9,0xF9,0x4D), //controlDisabled
+ QColor(0x00,0x00,0x00,0x0F), //controlStrokeDefault
+ QColor(0x00,0x00,0x00,0x29), //controlStrokeSecondary
+ QColor(0x00,0x5F,0xB8,0xFF), //accentDefault
+ QColor(0x00,0x00,0x00,0x37), //accentDisabled
+ QColor(0x00,0x5F,0xB8,0xE6), //accentSecondary
+};
+
+const static QColor WINUI3ColorsDark[] {
+ QColor(0x20,0x20,0x20,0xFF), //solidBackgroundColor
+ QColor(0xFF,0xFF,0xFF,0xFF), //textPrimary
+ QColor(0xFF,0xFF,0xFF,0xC5), //textSecondary
+ QColor(0xFF,0xFF,0xFF,0x5D), //textDisabled
+ QColor(0x00,0x00,0x00,0xFF), //textOnAccentPrimary
+ QColor(0x00,0x00,0x00,0x80), //textOnAccentSecondary
+ QColor(0xFF,0xFF,0xFF,0x87), //textOnAccentDisabled
+ QColor(0xFF,0xFF,0xFF,0x0F), //controlDefault
+ QColor(0xFF,0xFF,0xFF,0x11), //controlDisabled
+ QColor(0xFF,0xFF,0xFF,0x12), //controlStrokeDefault
+ QColor(0xFF,0xFF,0xFF,0x18), //controlStrokeSecondary
+ QColor(0x60,0xCD,0xFF,0xFF), //accentDefault
+ QColor(0xFF,0xFF,0xFF,0x28), //accentDisabled
+ QColor(0x60,0xCD,0xFF,0xE6) // accentSecondary
+};
+
+const static QColor* WINUI3Colors[] {
+ WINUI3ColorsLight,
+ WINUI3ColorsDark
+};
+
+static void populateSystemPalette(QPalette &palette)
+{
+ const auto colorSchemeIndex = QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Light ? 0 : 1;
+
+ palette.setColor(QPalette::All, QPalette::Window, WINUI3Colors[colorSchemeIndex][solidBackground]);
+
+ palette.setColor(QPalette::All, QPalette::WindowText, WINUI3Colors[colorSchemeIndex][textPrimary]);
+ palette.setColor(QPalette::Disabled, QPalette::WindowText, WINUI3Colors[colorSchemeIndex][textDisabled]);
+
+ palette.setColor(QPalette::All, QPalette::Text, WINUI3Colors[colorSchemeIndex][textPrimary]);
+ palette.setColor(QPalette::Disabled, QPalette::Text, WINUI3Colors[colorSchemeIndex][textDisabled]);
+
+ palette.setColor(QPalette::All, QPalette::PlaceholderText, WINUI3Colors[colorSchemeIndex][textSecondary]);
+ palette.setColor(QPalette::Disabled, QPalette::PlaceholderText, WINUI3Colors[colorSchemeIndex][textDisabled]);
+
+ palette.setColor(QPalette::All, QPalette::Button, WINUI3Colors[colorSchemeIndex][controlDefault]);
+ palette.setColor(QPalette::Disabled, QPalette::Button, WINUI3Colors[colorSchemeIndex][controlDisabled]);
+ palette.setColor(QPalette::All, QPalette::ButtonText, WINUI3Colors[colorSchemeIndex][textPrimary]);
+ palette.setColor(QPalette::Disabled, QPalette::ButtonText, WINUI3Colors[colorSchemeIndex][textDisabled]);
+ palette.setColor(QPalette::All, QPalette::BrightText, WINUI3Colors[colorSchemeIndex][textSecondary]);
+
+ palette.setColor(QPalette::All, QPalette::Highlight, WINUI3Colors[colorSchemeIndex][accentDefault]);
+ palette.setColor(QPalette::Disabled, QPalette::Highlight, WINUI3Colors[colorSchemeIndex][accentDisabled]);
+ palette.setColor(QPalette::All, QPalette::Accent, WINUI3Colors[colorSchemeIndex][accentDefault]);
+ palette.setColor(QPalette::Disabled, QPalette::Accent, WINUI3Colors[colorSchemeIndex][accentDisabled]);
+
+ palette.setColor(QPalette::All, QPalette::HighlightedText, WINUI3Colors[colorSchemeIndex][textOnAccentPrimary]);
+ palette.setColor(QPalette::Disabled, QPalette::HighlightedText, WINUI3Colors[colorSchemeIndex][textOnAccentDisabled]);
+}
+
+static void populateSystemFont(QFont &systemFont)
+{
+ const QLatin1String segoeUiFamilyName("Segoe UI Variable");
+ if (QFontDatabase::families().contains(segoeUiFamilyName)) {
+ const QFont font(segoeUiFamilyName);
+ const QStringList families{font.family()};
+ systemFont.setFamilies(families);
+ }
+ systemFont.setWeight(QFont::Weight::Normal);
+ systemFont.setPixelSize(14);
+}
+
+void QQuickFluentWinUI3Theme::updatePalette(QPalette &palette)
+{
+ populateSystemPalette(palette);
+}
+
+void QQuickFluentWinUI3Theme::initialize(QQuickTheme *theme)
+{
+ QFont systemFont;
+ populateSystemFont(systemFont);
+ theme->setFont(QQuickTheme::System, systemFont);
+ QPalette systemPalette;
+ updatePalette(systemPalette);
+ theme->setPalette(QQuickTheme::System, systemPalette);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quickcontrols/fluentwinui3/qquickfluentwinui3theme_p.h b/src/quickcontrols/fluentwinui3/qquickfluentwinui3theme_p.h
new file mode 100644
index 0000000000..bf098cec82
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/qquickfluentwinui3theme_p.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQUICKFLUENTWINUI3THEME_P_H
+#define QQUICKFLUENTWINUI3THEME_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTheme;
+class QPalette;
+class QQuickFluentWinUI3Theme
+{
+public:
+ static void initialize(QQuickTheme *theme);
+ static void updatePalette(QPalette &palette);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFLUENTWINUI3THEME_P_H
diff --git a/src/quickcontrols/fluentwinui3/qtquickcontrols2fluentwinui3styleplugin.cpp b/src/quickcontrols/fluentwinui3/qtquickcontrols2fluentwinui3styleplugin.cpp
new file mode 100644
index 0000000000..6baf774dd3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/qtquickcontrols2fluentwinui3styleplugin.cpp
@@ -0,0 +1,56 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquickfluentwinui3theme_p.h"
+
+#include <QtQuickControls2/private/qquickstyleplugin_p.h>
+#include <QtQuickControls2/private/qquickstyleplugin_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+QT_BEGIN_NAMESPACE
+
+extern void qml_register_types_QtQuick_Controls_FluentWinUI3();
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_Controls_FluentWinUI3);
+
+class QtQuickControls2FluentWinUI3StylePlugin : public QQuickStylePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuickControls2FluentWinUI3StylePlugin(QObject *parent = nullptr);
+
+ QString name() const override;
+ void initializeTheme(QQuickTheme *theme) override;
+ void updateTheme() override;
+
+ QQuickFluentWinUI3Theme theme;
+};
+
+QtQuickControls2FluentWinUI3StylePlugin::QtQuickControls2FluentWinUI3StylePlugin(QObject *parent) : QQuickStylePlugin(parent)
+{
+ volatile auto registration = &qml_register_types_QtQuick_Controls_FluentWinUI3;
+ Q_UNUSED(registration);
+}
+
+QString QtQuickControls2FluentWinUI3StylePlugin::name() const
+{
+ return QStringLiteral("FluentWinUI3");
+}
+
+void QtQuickControls2FluentWinUI3StylePlugin::initializeTheme(QQuickTheme *theme)
+{
+ this->theme.initialize(theme);
+}
+
+void QtQuickControls2FluentWinUI3StylePlugin::updateTheme()
+{
+ QQuickTheme *theme = QQuickTheme::instance();
+ QPalette palette;
+ this->theme.updatePalette(palette);
+ theme->setPalette(QQuickTheme::System, palette);
+}
+
+QT_END_NAMESPACE
+
+#include "qtquickcontrols2fluentwinui3styleplugin.moc"
diff --git a/src/quickcontrols/fusion/ComboBox.qml b/src/quickcontrols/fusion/ComboBox.qml
index 609f294d6f..decc43f1f7 100644
--- a/src/quickcontrols/fusion/ComboBox.qml
+++ b/src/quickcontrols/fusion/ComboBox.qml
@@ -116,6 +116,7 @@ T.ComboBox {
topMargin: 6
bottomMargin: 6
padding: 1
+ palette: control.palette
contentItem: ListView {
clip: true
diff --git a/src/quickcontrols/ios/CMakeLists.txt b/src/quickcontrols/ios/CMakeLists.txt
index c4c827677a..f3be4038a3 100644
--- a/src/quickcontrols/ios/CMakeLists.txt
+++ b/src/quickcontrols/ios/CMakeLists.txt
@@ -5,6 +5,8 @@
## qtquickcontrols2iosstyleplugin Plugin:
#####################################################################
+add_subdirectory(impl)
+
set(qml_files
"Slider.qml"
"RangeSlider.qml"
@@ -108,8 +110,6 @@ qt_internal_add_resource(qtquickcontrols2iosstyleplugin "qmake_qtquickcontrols2i
${qmake_qtquickcontrols2iosstyleplugin_resource_files}
)
-add_subdirectory(impl)
-
_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2iosstyleplugin
qtquickcontrols2iosstyleimplplugin)
diff --git a/src/quickcontrols/macos/CMakeLists.txt b/src/quickcontrols/macos/CMakeLists.txt
index 376c093f27..4c3ff540a4 100644
--- a/src/quickcontrols/macos/CMakeLists.txt
+++ b/src/quickcontrols/macos/CMakeLists.txt
@@ -5,6 +5,8 @@
## qtquickcontrols2macosstyleplugin Plugin:
#####################################################################
+add_subdirectory(impl)
+
set(qml_files
"BusyIndicator.qml"
"Button.qml"
@@ -18,11 +20,17 @@ set(qml_files
"Frame.qml"
"GroupBox.qml"
"ItemDelegate.qml"
+ "Menu.qml"
+ "MenuBar.qml"
+ "MenuBarItem.qml"
+ "MenuItem.qml"
+ "MenuSeparator.qml"
"ProgressBar.qml"
"RadioButton.qml"
"RadioDelegate.qml"
"RangeSlider.qml"
"ScrollBar.qml"
+ "ScrollIndicator.qml"
"ScrollView.qml"
"SelectionRectangle.qml"
"Slider.qml"
@@ -60,6 +68,12 @@ qt_internal_add_qml_module(qtquickcontrols2macosstyleplugin
images/busyindicator-light.webp
images/busyindicator-light@2x.webp
images/busyindicator-light@3x.webp
+ images/checkmark.png
+ images/checkmark@2x.png
+ images/checkmark@3x.png
+ images/menuarrow.png
+ images/menuarrow@2x.png
+ images/menuarrow@3x.png
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
@@ -73,8 +87,6 @@ qt_internal_add_qml_module(qtquickcontrols2macosstyleplugin
Qt::QuickTemplates2Private
)
-add_subdirectory(impl)
-
# Native style is a dependency of the macOS style.
_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2macosstyleplugin
qtquickcontrols2nativestyleplugin)
diff --git a/src/quickcontrols/macos/Menu.qml b/src/quickcontrols/macos/Menu.qml
new file mode 100644
index 0000000000..5004a44c42
--- /dev/null
+++ b/src/quickcontrols/macos/Menu.qml
@@ -0,0 +1,79 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Window
+import QtQuick.Effects
+
+T.Menu {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ // The insets are found by examining the MultiEffect.itemRect, which
+ // contains the drop shadow offsets. QQuickPopup will subract these insets when
+ // it opens up the menu so that the top left corner of the background ends up at
+ // the requested popup position.
+ // Note: the insets are hard-coded to avoid a binding loop to implicit size.
+ leftInset: 32
+ topInset: 32
+ rightInset: 32
+ bottomInset: 32
+ leftPadding: leftInset + 5
+ rightPadding: rightInset + 5
+ topPadding: topInset + 5
+ bottomPadding: bottomInset + 5
+ margins: 0
+ overlap: 4
+
+ delegate: MenuItem { }
+
+ contentItem: ListView {
+ implicitHeight: contentHeight
+ model: control.contentModel
+ interactive: Window.window
+ ? contentHeight + control.topPadding + control.bottomPadding > control.height
+ : false
+ currentIndex: control.currentIndex
+ spacing: 2
+
+ ScrollIndicator.vertical: ScrollIndicator {}
+ }
+
+ background: MultiEffect {
+ implicitWidth: 200
+ implicitHeight: 20
+ source: Rectangle {
+ width: control.background.width
+ height: control.background.height
+ radius: 5
+ color: Qt.styleHints.colorScheme === Qt.Light
+ ? Qt.darker(control.palette.window, 1.04)
+ : Qt.darker(control.palette.window, 1.2)
+ border.color: Qt.styleHints.colorScheme === Qt.Light
+ ? Qt.darker(control.palette.window, 1.4)
+ : Qt.lighter(control.palette.window, 2.0)
+ border.width: 0.5
+ visible: false
+ }
+ shadowScale: 1.04
+ shadowOpacity: Qt.styleHints.colorScheme === Qt.Light ? 0.15 : 0.2
+ shadowColor: 'black'
+ shadowEnabled: true
+ shadowHorizontalOffset: 0
+ shadowVerticalOffset: 7
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: "transparent"
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: "transparent"
+ }
+}
diff --git a/src/quickcontrols/macos/MenuBar.qml b/src/quickcontrols/macos/MenuBar.qml
new file mode 100644
index 0000000000..2b1e63fc30
--- /dev/null
+++ b/src/quickcontrols/macos/MenuBar.qml
@@ -0,0 +1,35 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.MenuBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ leftPadding: 6
+ rightPadding: 6
+ topPadding: 3
+ bottomPadding: 2
+ spacing: 4
+
+ delegate: MenuBarItem { }
+
+ contentItem: Row {
+ spacing: control.spacing
+ Repeater {
+ model: control.contentModel
+ }
+ }
+
+ background: Rectangle {
+ implicitHeight: 20
+ color: control.palette.window // window title bar color
+ }
+}
diff --git a/src/quickcontrols/macos/MenuBarItem.qml b/src/quickcontrols/macos/MenuBarItem.qml
new file mode 100644
index 0000000000..de7db7fd91
--- /dev/null
+++ b/src/quickcontrols/macos/MenuBarItem.qml
@@ -0,0 +1,46 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.MenuBarItem {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ leftInset: -4
+ rightInset: -4
+ padding: 6
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ background: Rectangle {
+ implicitWidth: 20
+ implicitHeight: 20
+
+ color: "black"
+ opacity: 0.1
+ radius: 4
+ visible: control.down || control.highlighted
+ }
+}
diff --git a/src/quickcontrols/macos/MenuItem.qml b/src/quickcontrols/macos/MenuItem.qml
new file mode 100644
index 0000000000..109c61e6a8
--- /dev/null
+++ b/src/quickcontrols/macos/MenuItem.qml
@@ -0,0 +1,75 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.macOS.impl
+
+T.MenuItem {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ leftPadding: 10
+ rightPadding: 10
+ topPadding: 3
+ bottomPadding: 3
+ spacing: 0
+
+ icon.width: 16
+ icon.height: 16
+
+ implicitTextPadding: control.checkable && control.indicator ? control.indicator.width + control.spacing : 0
+
+ contentItem: IconLabel {
+ readonly property real arrowPadding: control.subMenu && control.arrow ? control.arrow.width + control.spacing : 0
+ leftPadding: !control.mirrored ? control.textPadding : arrowPadding
+ rightPadding: control.mirrored ? control.textPadding : arrowPadding
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.down || control.highlighted ? "white" : control.palette.text
+ }
+
+ arrow: ColorImage {
+ x: control.mirrored ? control.padding : control.width - width - control.padding
+ y: control.topPadding + (control.availableHeight - height) / 2
+ width: 20
+
+ visible: control.subMenu
+ rotation: control.mirrored ? -180 : 0
+ scale: 0.6
+ color: control.palette.text
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/macOS/images/menuarrow.png"
+ fillMode: Image.Pad
+ }
+
+ indicator: CheckIndicator {
+ x: control.mirrored ? control.width - width - control.rightPadding : control.leftPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ control: control
+ visible: control.checkable
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 25
+ radius: 4
+
+ color: control.palette.accent
+ opacity: 0.7
+ visible: control.down || control.highlighted
+ }
+}
diff --git a/src/quickcontrols/macos/MenuSeparator.qml b/src/quickcontrols/macos/MenuSeparator.qml
new file mode 100644
index 0000000000..e9c0454ee6
--- /dev/null
+++ b/src/quickcontrols/macos/MenuSeparator.qml
@@ -0,0 +1,24 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.MenuSeparator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ horizontalPadding: 0
+ verticalPadding: 2
+
+ contentItem: Rectangle {
+ implicitWidth: 188
+ implicitHeight: 1
+ opacity: 0.7
+ color: palette.disabled.buttonText
+ }
+}
diff --git a/src/quickcontrols/macos/ScrollIndicator.qml b/src/quickcontrols/macos/ScrollIndicator.qml
new file mode 100644
index 0000000000..f8358eb1bf
--- /dev/null
+++ b/src/quickcontrols/macos/ScrollIndicator.qml
@@ -0,0 +1,42 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.ScrollIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 2
+
+ contentItem: Rectangle {
+ implicitWidth: 2
+ implicitHeight: 2
+
+ color: control.palette.mid
+ visible: control.size < 1.0
+ opacity: 0.0
+
+ states: State {
+ name: "active"
+ when: control.active
+ PropertyChanges { control.contentItem.opacity: 0.75 }
+ }
+
+ transitions: [
+ Transition {
+ from: "active"
+ SequentialAnimation {
+ PauseAnimation { duration: 450 }
+ NumberAnimation { target: control.contentItem; duration: 200; property: "opacity"; to: 0.0 }
+ }
+ }
+ ]
+ }
+}
diff --git a/src/quickcontrols/macos/images/checkmark.png b/src/quickcontrols/macos/images/checkmark.png
new file mode 100644
index 0000000000..c89fae5252
--- /dev/null
+++ b/src/quickcontrols/macos/images/checkmark.png
Binary files differ
diff --git a/src/quickcontrols/macos/images/checkmark@2x.png b/src/quickcontrols/macos/images/checkmark@2x.png
new file mode 100644
index 0000000000..9fdaa3285f
--- /dev/null
+++ b/src/quickcontrols/macos/images/checkmark@2x.png
Binary files differ
diff --git a/src/quickcontrols/macos/images/checkmark@3x.png b/src/quickcontrols/macos/images/checkmark@3x.png
new file mode 100644
index 0000000000..cc383aa5c0
--- /dev/null
+++ b/src/quickcontrols/macos/images/checkmark@3x.png
Binary files differ
diff --git a/src/quickcontrols/macos/images/menuarrow.png b/src/quickcontrols/macos/images/menuarrow.png
new file mode 100644
index 0000000000..4c5ac65585
--- /dev/null
+++ b/src/quickcontrols/macos/images/menuarrow.png
Binary files differ
diff --git a/src/quickcontrols/macos/images/menuarrow@2x.png b/src/quickcontrols/macos/images/menuarrow@2x.png
new file mode 100644
index 0000000000..6cfa8a1883
--- /dev/null
+++ b/src/quickcontrols/macos/images/menuarrow@2x.png
Binary files differ
diff --git a/src/quickcontrols/macos/images/menuarrow@3x.png b/src/quickcontrols/macos/images/menuarrow@3x.png
new file mode 100644
index 0000000000..1a6334e0d0
--- /dev/null
+++ b/src/quickcontrols/macos/images/menuarrow@3x.png
Binary files differ
diff --git a/src/quickcontrols/macos/impl/CMakeLists.txt b/src/quickcontrols/macos/impl/CMakeLists.txt
index 6d007f4d9f..f10db451bc 100644
--- a/src/quickcontrols/macos/impl/CMakeLists.txt
+++ b/src/quickcontrols/macos/impl/CMakeLists.txt
@@ -2,6 +2,7 @@
# SPDX-License-Identifier: BSD-3-Clause
set(qml_files
+ "CheckIndicator.qml"
"SwitchHandle.qml"
"SwitchIndicator.qml"
)
diff --git a/src/quickcontrols/macos/impl/CheckIndicator.qml b/src/quickcontrols/macos/impl/CheckIndicator.qml
new file mode 100644
index 0000000000..9a41895475
--- /dev/null
+++ b/src/quickcontrols/macos/impl/CheckIndicator.qml
@@ -0,0 +1,21 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+
+Item {
+ id: indicator
+ implicitWidth: 14
+ implicitHeight: 10
+
+ property Item control
+
+ ColorImage {
+ y: (parent.height - height) / 2
+ color: control.palette.text
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/macOS/images/checkmark.png"
+ visible: indicator.control.checkState === Qt.Checked
+ || (indicator.control.checked && indicator.control.checkState === undefined)
+ }
+}
diff --git a/src/quickcontrols/qquickstyle.cpp b/src/quickcontrols/qquickstyle.cpp
index 347a2ab179..5b715a6533 100644
--- a/src/quickcontrols/qquickstyle.cpp
+++ b/src/quickcontrols/qquickstyle.cpp
@@ -306,6 +306,7 @@ QSharedPointer<QSettings> QQuickStylePrivate::settings(const QString &group)
return QSharedPointer<QSettings>(settings);
}
#endif // QT_NO_SETTINGS
+ Q_UNUSED(group)
return QSharedPointer<QSettings>();
}
@@ -399,6 +400,7 @@ QStringList QQuickStylePrivate::builtInStyles()
return {
QLatin1String("Basic"),
QLatin1String("Fusion"),
+ QLatin1String("FluentWinUI3"),
QLatin1String("Imagine"),
#ifdef Q_OS_MACOS
QLatin1String("macOS"),
diff --git a/src/quickcontrols/qt_cmdline.cmake b/src/quickcontrols/qt_cmdline.cmake
index ed009c5407..6160f818f4 100644
--- a/src/quickcontrols/qt_cmdline.cmake
+++ b/src/quickcontrols/qt_cmdline.cmake
@@ -2,6 +2,7 @@
# SPDX-License-Identifier: BSD-3-Clause
qt_commandline_option(style-fusion TYPE boolean NAME quickcontrols2-fusion)
+qt_commandline_option(style-fluentwinui3 TYPE boolean NAME quickcontrols2-fluentwinui3)
qt_commandline_option(style-imagine TYPE boolean NAME quickcontrols2-imagine)
qt_commandline_option(style-ios TYPE boolean NAME quickcontrols2-ios)
qt_commandline_option(style-material TYPE boolean NAME quickcontrols2-material)
diff --git a/src/quickcontrols/windows/CMakeLists.txt b/src/quickcontrols/windows/CMakeLists.txt
index 55c57a956c..36e871abdb 100644
--- a/src/quickcontrols/windows/CMakeLists.txt
+++ b/src/quickcontrols/windows/CMakeLists.txt
@@ -15,10 +15,16 @@ set(qml_files
"Frame.qml"
"GroupBox.qml"
"ItemDelegate.qml"
+ "Menu.qml"
+ "MenuBar.qml"
+ "MenuBarItem.qml"
+ "MenuItem.qml"
+ "MenuSeparator.qml"
"ProgressBar.qml"
"RadioButton.qml"
"RadioDelegate.qml"
"RangeSlider.qml"
+ "ScrollIndicator.qml"
"SelectionRectangle.qml"
"Slider.qml"
"SpinBox.qml"
@@ -44,6 +50,13 @@ qt_internal_add_qml_module(qtquickcontrols2windowsstyleplugin
qtquickcontrols2windowsstyleplugin.cpp
QML_FILES
${qml_files}
+ RESOURCES
+ images/checkmark.png
+ images/checkmark@2x.png
+ images/checkmark@3x.png
+ images/menuarrow.png
+ images/menuarrow@2x.png
+ images/menuarrow@3x.png
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
diff --git a/src/quickcontrols/windows/Menu.qml b/src/quickcontrols/windows/Menu.qml
new file mode 100644
index 0000000000..0b110d7744
--- /dev/null
+++ b/src/quickcontrols/windows/Menu.qml
@@ -0,0 +1,74 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Window
+import QtQuick.Effects
+
+T.Menu {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ // The insets are found by examining the MultiEffect.itemRect, which
+ // contains the drop shadow offsets. QQuickPopup will subract these insets when
+ // it opens up the menu so that the top left corner of the background ends up at
+ // the requested popup position.
+ // Note: the insets are hard-coded to avoid a binding loop to implicit size.
+ leftInset: 32
+ topInset: 32
+ rightInset: 32
+ bottomInset: 32
+ leftPadding: leftInset + 5
+ rightPadding: rightInset + 5
+ topPadding: topInset + 5
+ bottomPadding: bottomInset + 5
+ margins: 0
+ overlap: 4
+
+ delegate: MenuItem { }
+
+ contentItem: ListView {
+ implicitHeight: contentHeight
+ model: control.contentModel
+ interactive: Window.window
+ ? contentHeight + control.topPadding + control.bottomPadding > control.height
+ : false
+ currentIndex: control.currentIndex
+ spacing: 2
+
+ ScrollIndicator.vertical: ScrollIndicator {}
+ }
+
+ background: MultiEffect {
+ implicitWidth: 200
+ implicitHeight: 20
+ source: Rectangle {
+ width: control.background.width
+ height: control.background.height
+ radius: 8
+ color: Qt.lighter(control.palette.window, 1.15)
+ border.color: Qt.darker(control.palette.window, 1.12)
+ visible: false
+ }
+ shadowScale: 1.04
+ shadowOpacity: 0.1
+ shadowColor: 'black'
+ shadowEnabled: true
+ shadowHorizontalOffset: 0
+ shadowVerticalOffset: 10
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: "transparent"
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: "transparent"
+ }
+}
diff --git a/src/quickcontrols/windows/MenuBar.qml b/src/quickcontrols/windows/MenuBar.qml
new file mode 100644
index 0000000000..ec998abde7
--- /dev/null
+++ b/src/quickcontrols/windows/MenuBar.qml
@@ -0,0 +1,35 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.MenuBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ leftPadding: 3
+ rightPadding: 3
+ topPadding: 3
+ bottomPadding: 3
+ spacing: 10
+
+ delegate: MenuBarItem { }
+
+ contentItem: Row {
+ spacing: control.spacing
+ Repeater {
+ model: control.contentModel
+ }
+ }
+
+ background: Rectangle {
+ implicitHeight: 20
+ color: "white" // window title bar color
+ }
+}
diff --git a/src/quickcontrols/windows/MenuBarItem.qml b/src/quickcontrols/windows/MenuBarItem.qml
new file mode 100644
index 0000000000..fe71542153
--- /dev/null
+++ b/src/quickcontrols/windows/MenuBarItem.qml
@@ -0,0 +1,47 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.MenuBarItem {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ topPadding: 8
+ bottomPadding: 8
+ leftPadding: 10
+ rightPadding: 10
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ background: Rectangle {
+ implicitWidth: 20
+ implicitHeight: 20
+
+ color: "black"
+ opacity: 0.05
+ radius: 4
+ visible: control.down || control.highlighted
+ }
+}
diff --git a/src/quickcontrols/windows/MenuItem.qml b/src/quickcontrols/windows/MenuItem.qml
new file mode 100644
index 0000000000..0d3c4f89f6
--- /dev/null
+++ b/src/quickcontrols/windows/MenuItem.qml
@@ -0,0 +1,74 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Windows.impl
+
+T.MenuItem {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ leftPadding: 10
+ rightPadding: 10
+ topPadding: 3
+ bottomPadding: 3
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ implicitTextPadding: control.checkable && control.indicator ? control.indicator.width + control.spacing : 0
+
+ contentItem: IconLabel {
+ readonly property real arrowPadding: control.subMenu && control.arrow ? control.arrow.width + control.spacing : 0
+ leftPadding: !control.mirrored ? control.textPadding : arrowPadding
+ rightPadding: control.mirrored ? control.textPadding : arrowPadding
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ arrow: ColorImage {
+ x: control.mirrored ? control.padding : control.width - width - control.padding
+ y: control.topPadding + (control.availableHeight - height) / 2
+ width: 20
+
+ visible: control.subMenu
+ rotation: control.mirrored ? -180 : 0
+ color: control.palette.text
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Windows/images/menuarrow.png"
+ fillMode: Image.Pad
+ }
+
+ indicator: CheckIndicator {
+ x: control.mirrored ? control.width - width - control.rightPadding : control.leftPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ control: control
+ visible: control.checkable
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 30
+ radius: 4
+
+ color: control.palette.dark
+ opacity: 0.1
+ visible: control.down || control.highlighted
+ }
+}
diff --git a/src/quickcontrols/windows/MenuSeparator.qml b/src/quickcontrols/windows/MenuSeparator.qml
new file mode 100644
index 0000000000..6559be9958
--- /dev/null
+++ b/src/quickcontrols/windows/MenuSeparator.qml
@@ -0,0 +1,23 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.MenuSeparator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ horizontalPadding: 0
+ verticalPadding: 2
+
+ contentItem: Rectangle {
+ implicitWidth: 188
+ implicitHeight: 1
+ color: control.palette.midlight
+ }
+}
diff --git a/src/quickcontrols/windows/ScrollIndicator.qml b/src/quickcontrols/windows/ScrollIndicator.qml
new file mode 100644
index 0000000000..f8358eb1bf
--- /dev/null
+++ b/src/quickcontrols/windows/ScrollIndicator.qml
@@ -0,0 +1,42 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.ScrollIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 2
+
+ contentItem: Rectangle {
+ implicitWidth: 2
+ implicitHeight: 2
+
+ color: control.palette.mid
+ visible: control.size < 1.0
+ opacity: 0.0
+
+ states: State {
+ name: "active"
+ when: control.active
+ PropertyChanges { control.contentItem.opacity: 0.75 }
+ }
+
+ transitions: [
+ Transition {
+ from: "active"
+ SequentialAnimation {
+ PauseAnimation { duration: 450 }
+ NumberAnimation { target: control.contentItem; duration: 200; property: "opacity"; to: 0.0 }
+ }
+ }
+ ]
+ }
+}
diff --git a/src/quickcontrols/windows/images/checkmark.png b/src/quickcontrols/windows/images/checkmark.png
new file mode 100644
index 0000000000..35fe52c8c0
--- /dev/null
+++ b/src/quickcontrols/windows/images/checkmark.png
Binary files differ
diff --git a/src/quickcontrols/windows/images/checkmark@2x.png b/src/quickcontrols/windows/images/checkmark@2x.png
new file mode 100644
index 0000000000..fb7096b4b5
--- /dev/null
+++ b/src/quickcontrols/windows/images/checkmark@2x.png
Binary files differ
diff --git a/src/quickcontrols/windows/images/checkmark@3x.png b/src/quickcontrols/windows/images/checkmark@3x.png
new file mode 100644
index 0000000000..e0c2790607
--- /dev/null
+++ b/src/quickcontrols/windows/images/checkmark@3x.png
Binary files differ
diff --git a/src/quickcontrols/windows/images/menuarrow.png b/src/quickcontrols/windows/images/menuarrow.png
new file mode 100644
index 0000000000..b504351fe1
--- /dev/null
+++ b/src/quickcontrols/windows/images/menuarrow.png
Binary files differ
diff --git a/src/quickcontrols/windows/images/menuarrow@2x.png b/src/quickcontrols/windows/images/menuarrow@2x.png
new file mode 100644
index 0000000000..fa9082d0c0
--- /dev/null
+++ b/src/quickcontrols/windows/images/menuarrow@2x.png
Binary files differ
diff --git a/src/quickcontrols/windows/images/menuarrow@3x.png b/src/quickcontrols/windows/images/menuarrow@3x.png
new file mode 100644
index 0000000000..acb626246d
--- /dev/null
+++ b/src/quickcontrols/windows/images/menuarrow@3x.png
Binary files differ
diff --git a/src/quickcontrols/windows/impl/CMakeLists.txt b/src/quickcontrols/windows/impl/CMakeLists.txt
index fb1b0f2358..8b031b7a8d 100644
--- a/src/quickcontrols/windows/impl/CMakeLists.txt
+++ b/src/quickcontrols/windows/impl/CMakeLists.txt
@@ -2,6 +2,7 @@
# SPDX-License-Identifier: BSD-3-Clause
set(qml_files
+ "CheckIndicator.qml"
"SwitchIndicator.qml"
)
diff --git a/src/quickcontrols/windows/impl/CheckIndicator.qml b/src/quickcontrols/windows/impl/CheckIndicator.qml
new file mode 100644
index 0000000000..818336dfdf
--- /dev/null
+++ b/src/quickcontrols/windows/impl/CheckIndicator.qml
@@ -0,0 +1,21 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+
+Item {
+ id: indicator
+ implicitWidth: 14
+ implicitHeight: 10
+
+ property Item control
+
+ ColorImage {
+ y: (parent.height - height) / 2
+ color: control.palette.text
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Windows/images/checkmark.png"
+ visible: indicator.control.checkState === Qt.Checked
+ || (indicator.control.checked && indicator.control.checkState === undefined)
+ }
+}
diff --git a/src/quickcontrolsimpl/qquickcolorimage.cpp b/src/quickcontrolsimpl/qquickcolorimage.cpp
index 5ad6d7d296..dcd87b5e72 100644
--- a/src/quickcontrolsimpl/qquickcolorimage.cpp
+++ b/src/quickcontrolsimpl/qquickcolorimage.cpp
@@ -57,12 +57,12 @@ void QQuickColorImage::pixmapChange()
QQuickImage::pixmapChange();
if (m_color.alpha() > 0 && m_color != m_defaultColor) {
QQuickImageBasePrivate *d = static_cast<QQuickImageBasePrivate *>(QQuickItemPrivate::get(this));
- QImage image = d->pix.image();
+ QImage image = d->currentPix->image();
if (!image.isNull()) {
QPainter painter(&image);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.fillRect(image.rect(), m_color);
- d->pix.setImage(image);
+ d->currentPix->setImage(image);
}
}
}
diff --git a/src/quickcontrolsimpl/qquickiconimage.cpp b/src/quickcontrolsimpl/qquickiconimage.cpp
index 24bb752ebd..c2af3e0539 100644
--- a/src/quickcontrolsimpl/qquickiconimage.cpp
+++ b/src/quickcontrolsimpl/qquickiconimage.cpp
@@ -82,7 +82,7 @@ void QQuickIconImagePrivate::updateFillMode()
updatingFillMode = true;
- const QSize pixmapSize = QSize(pix.width(), pix.height()) / calculateDevicePixelRatio();
+ const QSize pixmapSize = QSize(currentPix->width(), currentPix->height()) / calculateDevicePixelRatio();
if (pixmapSize.width() > q->width() || pixmapSize.height() > q->height())
q->setFillMode(QQuickImage::PreserveAspectFit);
else
@@ -186,12 +186,12 @@ void QQuickIconImage::pixmapChange()
// Don't apply the color if we're recursing (updateFillMode() can cause us to recurse).
if (!d->updatingFillMode && d->color.alpha() > 0) {
- QImage image = d->pix.image();
+ QImage image = d->currentPix->image();
if (!image.isNull()) {
QPainter painter(&image);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.fillRect(image.rect(), d->color);
- d->pix.setImage(image);
+ d->currentPix->setImage(image);
}
}
}
diff --git a/src/quickcontrolsimpl/qquickninepatchimage.cpp b/src/quickcontrolsimpl/qquickninepatchimage.cpp
index d6238d2ccd..4d34123014 100644
--- a/src/quickcontrolsimpl/qquickninepatchimage.cpp
+++ b/src/quickcontrolsimpl/qquickninepatchimage.cpp
@@ -399,13 +399,13 @@ void QQuickNinePatchImage::pixmapChange()
if (!d->resetNode)
d->resetNode = d->ninePatch.isNull();
- d->ninePatch = d->pix.image();
+ d->ninePatch = d->currentPix->image();
if (d->ninePatch.depth() != 32)
d->ninePatch = std::move(d->ninePatch).convertToFormat(QImage::Format_ARGB32);
int w = d->ninePatch.width();
int h = d->ninePatch.height();
- d->pix.setImage(QImage(d->ninePatch.constBits() + 4 * (w + 1), w - 2, h - 2, d->ninePatch.bytesPerLine(), d->ninePatch.format()));
+ d->currentPix->setImage(QImage(d->ninePatch.constBits() + 4 * (w + 1), w - 2, h - 2, d->ninePatch.bytesPerLine(), d->ninePatch.format()));
d->updatePatches();
} else {
@@ -447,7 +447,7 @@ QSGNode *QQuickNinePatchImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNode
return QQuickImage::updatePaintNode(oldNode, data);
QSizeF sz = size();
- QImage image = d->pix.image();
+ QImage image = d->currentPix->image();
if (!sz.isValid() || image.isNull()) {
if (d->provider)
d->provider->updateTexture(nullptr);
diff --git a/src/quicklayouts/qquicklayout.cpp b/src/quicklayouts/qquicklayout.cpp
index f38bdfd396..e3d24571d8 100644
--- a/src/quicklayouts/qquicklayout.cpp
+++ b/src/quicklayouts/qquicklayout.cpp
@@ -80,6 +80,8 @@ QQuickLayoutAttached::QQuickLayoutAttached(QObject *parent)
m_fillHeight(false),
m_isFillWidthSet(false),
m_isFillHeightSet(false),
+ m_isUseDefaultSizePolicySet(false),
+ m_useDefaultSizePolicy(QQuickLayout::SizePolicyExplicit),
m_isMinimumWidthSet(false),
m_isMinimumHeightSet(false),
m_isMaximumWidthSet(false),
@@ -340,6 +342,30 @@ void QQuickLayoutAttached::setFillHeight(bool fill)
}
/*!
+ \qmlattachedproperty enumeration Layout::useDefaultSizePolicy
+ \since 6.8
+
+ This property allows the user to configure the layout size policy at the component
+ level.
+
+ The default value will be inherited by querying the application attribute
+ \l Qt::AA_QtQuickUseDefaultSizePolicy. You can use this property to override that value.
+
+ \value Layout.SizePolicyImplicit
+ The item in the layout uses implicit or built-in size policy
+ \value Layout.SizePolicyExplicit
+ The item in the layout don't use implicit size policies.
+*/
+void QQuickLayoutAttached::setUseDefaultSizePolicy(QQuickLayout::SizePolicy sizePolicy)
+{
+ m_isUseDefaultSizePolicySet = true;
+ if (m_useDefaultSizePolicy != sizePolicy) {
+ m_useDefaultSizePolicy = sizePolicy;
+ emit useDefaultSizePolicyChanged();
+ }
+}
+
+/*!
\qmlattachedproperty int Layout::row
This property allows you to specify the row position of an item in a \l GridLayout.
@@ -1253,29 +1279,33 @@ void QQuickLayout::effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSiz
*/
QLayoutPolicy::Policy QQuickLayout::effectiveSizePolicy_helper(QQuickItem *item, Qt::Orientation orientation, QQuickLayoutAttached *info)
{
- bool fillExtent([&]{
- QLayoutPolicy::Policy policy{QLayoutPolicy::Fixed};
- if (item && QGuiApplication::testAttribute(Qt::AA_QtQuickUseDefaultSizePolicy)) {
- QLayoutPolicy sizePolicy = QQuickItemPrivate::get(item)->sizePolicy();
- policy = (orientation == Qt::Horizontal) ? sizePolicy.horizontalPolicy() : sizePolicy.verticalPolicy();
- }
- return (policy == QLayoutPolicy::Preferred);
- }());
-
+ QLayoutPolicy::Policy pol{QLayoutPolicy::Fixed};
bool isSet = false;
if (info) {
if (orientation == Qt::Horizontal) {
isSet = info->isFillWidthSet();
- if (isSet) fillExtent = info->fillWidth();
+ if (isSet && info->fillWidth())
+ pol = QLayoutPolicy::Preferred;
} else {
isSet = info->isFillHeightSet();
- if (isSet) fillExtent = info->fillHeight();
+ if (isSet && info->fillHeight())
+ pol = QLayoutPolicy::Preferred;
+ }
+ }
+ if (!isSet && item) {
+ auto effectiveUseDefaultSizePolicy = [info]() {
+ return info ? info->useDefaultSizePolicy() == QQuickLayout::SizePolicyImplicit
+ : QGuiApplication::testAttribute(Qt::AA_QtQuickUseDefaultSizePolicy);
+ };
+ if (qobject_cast<QQuickLayout*>(item)) {
+ pol = QLayoutPolicy::Preferred;
+ } else if (effectiveUseDefaultSizePolicy()) {
+ QLayoutPolicy sizePolicy = QQuickItemPrivate::get(item)->sizePolicy();
+ pol = (orientation == Qt::Horizontal) ? sizePolicy.horizontalPolicy() : sizePolicy.verticalPolicy();
}
}
- if (!isSet && qobject_cast<QQuickLayout*>(item))
- fillExtent = true;
- return fillExtent ? QLayoutPolicy::Preferred : QLayoutPolicy::Fixed;
+ return pol;
}
void QQuickLayout::_q_dumpLayoutTree() const
diff --git a/src/quicklayouts/qquicklayout_p.h b/src/quicklayouts/qquicklayout_p.h
index f0ccc6dbf5..2f29c783d5 100644
--- a/src/quicklayouts/qquicklayout_p.h
+++ b/src/quicklayouts/qquicklayout_p.h
@@ -53,6 +53,12 @@ public:
ApplySizeHints = 0b010
};
+ enum SizePolicy {
+ SizePolicyImplicit = 1,
+ SizePolicyExplicit
+ };
+ Q_ENUM(SizePolicy)
+
Q_DECLARE_FLAGS(EnsureLayoutItemsUpdatedOptions, EnsureLayoutItemsUpdatedOption)
explicit QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent = nullptr);
@@ -168,6 +174,7 @@ class Q_QUICKLAYOUTS_EXPORT QQuickLayoutAttached : public QObject
Q_PROPERTY(qreal maximumHeight READ maximumHeight WRITE setMaximumHeight NOTIFY maximumHeightChanged FINAL)
Q_PROPERTY(bool fillHeight READ fillHeight WRITE setFillHeight NOTIFY fillHeightChanged FINAL)
Q_PROPERTY(bool fillWidth READ fillWidth WRITE setFillWidth NOTIFY fillWidthChanged FINAL)
+ Q_PROPERTY(QQuickLayout::SizePolicy useDefaultSizePolicy READ useDefaultSizePolicy WRITE setUseDefaultSizePolicy NOTIFY useDefaultSizePolicyChanged FINAL)
Q_PROPERTY(int row READ row WRITE setRow NOTIFY rowChanged FINAL)
Q_PROPERTY(int column READ column WRITE setColumn NOTIFY columnChanged FINAL)
Q_PROPERTY(int rowSpan READ rowSpan WRITE setRowSpan NOTIFY rowSpanChanged FINAL)
@@ -213,21 +220,31 @@ public:
void setMaximumImplicitSize(const QSizeF &sz);
bool fillWidth() const {
- if (auto *itemPriv = itemForSizePolicy(m_isFillWidthSet))
- return (itemPriv->sizePolicy().horizontalPolicy() == QLayoutPolicy::Preferred);
+ if (auto *itemPriv = itemForSizePolicy(m_isFillWidthSet)) {
+ QLayoutPolicy::Policy hPolicy = itemPriv->sizePolicy().horizontalPolicy();
+ return hPolicy & QLayoutPolicy::GrowFlag;
+ }
return m_fillWidth;
}
void setFillWidth(bool fill);
bool isFillWidthSet() const { return m_isFillWidthSet; }
bool fillHeight() const {
- if (auto *itemPriv = itemForSizePolicy(m_isFillHeightSet))
- return (itemPriv->sizePolicy().verticalPolicy() == QLayoutPolicy::Preferred);
+ if (auto *itemPriv = itemForSizePolicy(m_isFillHeightSet)) {
+ QLayoutPolicy::Policy vPolicy = itemPriv->sizePolicy().verticalPolicy();
+ return vPolicy & QLayoutPolicy::GrowFlag;
+ }
return m_fillHeight;
}
void setFillHeight(bool fill);
bool isFillHeightSet() const { return m_isFillHeightSet; }
+ QQuickLayout::SizePolicy useDefaultSizePolicy() const {
+ const bool appDefSizePolicy = QGuiApplication::testAttribute(Qt::AA_QtQuickUseDefaultSizePolicy);
+ return (m_isUseDefaultSizePolicySet ? m_useDefaultSizePolicy : (appDefSizePolicy ? QQuickLayout::SizePolicyImplicit : QQuickLayout::SizePolicyExplicit));
+ }
+ void setUseDefaultSizePolicy(QQuickLayout::SizePolicy sizePolicy);
+
int row() const { return qMax(m_row, 0); }
void setRow(int row);
bool isRowSet() const { return m_row >= 0; }
@@ -330,6 +347,7 @@ Q_SIGNALS:
void maximumHeightChanged();
void fillWidthChanged();
void fillHeightChanged();
+ void useDefaultSizePolicyChanged();
void leftMarginChanged();
void topMarginChanged();
void rightMarginChanged();
@@ -371,6 +389,8 @@ private:
unsigned m_fillHeight : 1;
unsigned m_isFillWidthSet : 1;
unsigned m_isFillHeightSet : 1;
+ unsigned m_isUseDefaultSizePolicySet: 1;
+ QQuickLayout::SizePolicy m_useDefaultSizePolicy;
unsigned m_isMinimumWidthSet : 1;
unsigned m_isMinimumHeightSet : 1;
// preferredWidth and preferredHeight are always explicit, since
diff --git a/src/quicklayouts/qquicklinearlayout.cpp b/src/quicklayouts/qquicklinearlayout.cpp
index 2fa3c7e820..41f45259ea 100644
--- a/src/quicklayouts/qquicklinearlayout.cpp
+++ b/src/quicklayouts/qquicklinearlayout.cpp
@@ -441,7 +441,7 @@ void QQuickGridLayoutBase::itemVisibilityChanged(QQuickItem *item)
void QQuickGridLayoutBase::rearrange(const QSizeF &size)
{
Q_D(QQuickGridLayoutBase);
- if (!isReady())
+ if (!isReady() || !size.isValid())
return;
qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::rearrange" << d->m_recurRearrangeCounter << this;
diff --git a/src/quicknativestyle/qstyle/qquickcommonstyle.cpp b/src/quicknativestyle/qstyle/qquickcommonstyle.cpp
index 530dc24f84..02bd1a694c 100644
--- a/src/quicknativestyle/qstyle/qquickcommonstyle.cpp
+++ b/src/quicknativestyle/qstyle/qquickcommonstyle.cpp
@@ -4443,7 +4443,7 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt) const
ret = int(QStyleHelper::dpiScaled(13, opt));
break;
case PM_MessageBoxIconSize:
-#ifdef Q_OS_MAC
+#ifdef Q_OS_APPLE
if (QGuiApplication::desktopSettingsAware()) {
ret = 64; // No DPI scaling, it's handled elsewhere.
} else
@@ -5662,7 +5662,7 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption
if (!icon.isNull())
return icon;
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_MACOS)
if (QGuiApplication::desktopSettingsAware()) {
switch (standardIcon) {
case SP_DirIcon: {
@@ -5730,7 +5730,7 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption
break;
}
} // if (QGuiApplication::desktopSettingsAware())
-#endif // Q_OS_MAC
+#endif // Q_OS_MACOS
switch (standardIcon) {
#ifndef QT_NO_IMAGEFORMAT_PNG
diff --git a/src/quickshapes/CMakeLists.txt b/src/quickshapes/CMakeLists.txt
index 7b52826751..f9fbfb75e7 100644
--- a/src/quickshapes/CMakeLists.txt
+++ b/src/quickshapes/CMakeLists.txt
@@ -52,6 +52,8 @@ qt_internal_add_shaders(QuickShapesPrivate "qtquickshapes_shaders"
"shaders_ng/radialgradient.frag"
"shaders_ng/conicalgradient.vert"
"shaders_ng/conicalgradient.frag"
+ "shaders_ng/texturefill.vert"
+ "shaders_ng/texturefill.frag"
"shaders_ng/wireframe.frag"
"shaders_ng/wireframe.vert"
)
diff --git a/src/quickshapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp
index 96f83b9af6..c254169e92 100644
--- a/src/quickshapes/qquickshape.cpp
+++ b/src/quickshapes/qquickshape.cpp
@@ -88,7 +88,8 @@ QQuickShapeStrokeFillParams::QQuickShapeStrokeFillParams()
capStyle(QQuickShapePath::SquareCap),
strokeStyle(QQuickShapePath::SolidLine),
dashOffset(0),
- fillGradient(nullptr)
+ fillGradient(nullptr),
+ fillItem(nullptr)
{
dashPattern << 4 << 2; // 4 * strokeWidth dash followed by 2 * strokeWidth space
}
@@ -240,6 +241,9 @@ void QQuickShapePath::setStrokeWidth(qreal w)
When set to \c transparent, no filling occurs.
The default value is \c white.
+
+ \note If either \l fillGradient or \l fillItem are set to something other than \c null, these
+ will take precedence over \c fillColor. The \c fillColor will be ignored in this case.
*/
QColor QQuickShapePath::fillColor() const
@@ -474,14 +478,14 @@ void QQuickShapePath::setDashPattern(const QVector<qreal> &array)
\qmlproperty ShapeGradient QtQuick.Shapes::ShapePath::fillGradient
This property defines the fill gradient. By default no gradient is enabled
- and the value is \c null. In this case the fill uses a solid color based
- on the value of ShapePath.fillColor.
-
- When set, ShapePath.fillColor is ignored and filling is done using one of
- the ShapeGradient subtypes.
+ and the value is \c null. In this case the fill will either be based on the \l fillItem
+ property if it is set, and otherwise the \l{fillColor} property will be used.
\note The Gradient type cannot be used here. Rather, prefer using one of
the advanced subtypes, like LinearGradient.
+
+ \note If set to something other than \c{null}, the \c fillGradient will take precedence over
+ both \l fillItem and \l fillColor.
*/
QQuickShapeGradient *QQuickShapePath::fillGradient() const
@@ -506,6 +510,11 @@ void QQuickShapePath::setFillGradient(QQuickShapeGradient *gradient)
}
}
+void QQuickShapePath::resetFillGradient()
+{
+ setFillGradient(nullptr);
+}
+
void QQuickShapePathPrivate::_q_fillGradientChanged()
{
Q_Q(QQuickShapePath);
@@ -513,9 +522,58 @@ void QQuickShapePathPrivate::_q_fillGradientChanged()
emit q->shapePathChanged();
}
-void QQuickShapePath::resetFillGradient()
+/*!
+ \qmlproperty Item QtQuick.Shapes::ShapePath::fillItem
+ \since 6.8
+
+ This property defines another Qt Quick Item to use as fill by the shape. The item must be
+ texture provider (such as a \l {Item Layers} {layered item}, a \l{ShaderEffectSource} or an
+ \l{Image}). If it is not a valid texture provider, this property will be ignored.
+
+ \note When using a layered item as a \c fillItem, you may see pixelation effects when
+ transforming the fill. Setting the \l layer.smooth property to true will give better visual
+ results in this case.
+
+ By default no fill item is set and the value is \c null.
+
+ \note If set to something other than \c null, the \c fillItem property takes precedence over
+ \l fillColor. The \l fillGradient property in turn takes precedence over both \c fillItem and
+ \l{fillColor}.
+ */
+
+QQuickItem *QQuickShapePath::fillItem() const
{
- setFillGradient(nullptr);
+ Q_D(const QQuickShapePath);
+ return d->sfp.fillItem;
+}
+
+void QQuickShapePath::setFillItem(QQuickItem *fillItem)
+{
+ Q_D(QQuickShapePath);
+ if (d->sfp.fillItem != fillItem) {
+ if (d->sfp.fillItem != nullptr) {
+ qmlobject_disconnect(d->sfp.fillItem, QQuickItem, SIGNAL(destroyed()),
+ this, QQuickShapePath, SLOT(_q_fillItemDestroyed()));
+ }
+ d->sfp.fillItem = fillItem;
+ if (d->sfp.fillItem != nullptr) {
+ qmlobject_connect(d->sfp.fillItem, QQuickItem, SIGNAL(destroyed()),
+ this, QQuickShapePath, SLOT(_q_fillItemDestroyed()));
+ }
+ emit fillItemChanged();
+
+ d->dirty |= QQuickShapePathPrivate::DirtyFillItem;
+ emit shapePathChanged();
+ }
+}
+
+void QQuickShapePathPrivate::_q_fillItemDestroyed()
+{
+ Q_Q(QQuickShapePath);
+ sfp.fillItem = nullptr;
+ dirty |= DirtyFillItem;
+ emit q->fillItemChanged();
+ emit q->shapePathChanged();
}
/*!
@@ -547,8 +605,8 @@ void QQuickShapePath::resetFillGradient()
This implies \c PathNonIntersecting.
Not all hints are logically independent, but the dependencies are not enforced.
- For example, \c PathIsLinear implies \c PathIsQuadratic, but it is valid to have \c PathIsLinear
- without \c PathIsQuadratic.
+ For example, \c PathLinear implies \c PathQuadratic, but it is valid to have \c PathLinear
+ without \c PathQuadratic.
The pathHints property describes a set of statements known to be true; the absence of a hint
does not necessarily mean that the corresponding statement is false.
@@ -570,6 +628,32 @@ void QQuickShapePath::setPathHints(PathHints newPathHints)
}
/*!
+ \qmlproperty matrix4x4 QtQuick.Shapes::ShapePath::fillTransform
+ \since 6.8
+
+ This property defines a transform to be applied to the path's fill pattern (gradient). It has
+ no effect if the fill is a solid color or transparent. By default no fill transform is enabled
+ and the value of this property is the \c identity matrix.
+*/
+
+QMatrix4x4 QQuickShapePath::fillTransform() const
+{
+ Q_D(const QQuickShapePath);
+ return d->sfp.fillTransform.matrix();
+}
+
+void QQuickShapePath::setFillTransform(const QMatrix4x4 &matrix)
+{
+ Q_D(QQuickShapePath);
+ if (d->sfp.fillTransform != matrix) {
+ d->sfp.fillTransform.setMatrix(matrix);
+ d->dirty |= QQuickShapePathPrivate::DirtyFillTransform;
+ emit fillTransformChanged();
+ emit shapePathChanged();
+ }
+}
+
+/*!
\qmltype Shape
//! \instantiates QQuickShape
\inqmlmodule QtQuick.Shapes
@@ -700,6 +784,12 @@ void QQuickShapePrivate::_q_shapePathChanged()
q->setImplicitSize(br.right(), br.bottom());
}
+void QQuickShapePrivate::handleSceneChange(QQuickWindow *w)
+{
+ if (renderer != nullptr)
+ renderer->handleSceneChange(w);
+}
+
void QQuickShapePrivate::setStatus(QQuickShape::Status newStatus)
{
Q_Q(QQuickShape);
@@ -1164,6 +1254,7 @@ void QQuickShape::itemChange(ItemChange change, const ItemChangeData &data)
for (int i = 0; i < d->sp.size(); ++i)
QQuickShapePathPrivate::get(d->sp[i])->dirty = QQuickShapePathPrivate::DirtyAll;
d->_q_shapePathChanged();
+ d->handleSceneChange(data.window);
}
QQuickItem::itemChange(change, data);
@@ -1214,7 +1305,10 @@ QSGNode *QQuickShape::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
ty = (height() - h) / 2;
fillModeTransform.translate(tx / xScale, ty / yScale);
}
- static_cast<QSGTransformNode *>(node)->setMatrix(fillModeTransform);
+
+ QSGTransformNode *transformNode = static_cast<QSGTransformNode *>(node);
+ if (fillModeTransform != transformNode->matrix())
+ transformNode->setMatrix(fillModeTransform);
}
return node;
}
@@ -1368,6 +1462,18 @@ void QQuickShapePrivate::sync()
renderer->setStrokeStyle(i, p->strokeStyle(), p->dashOffset(), p->dashPattern());
if (dirty & QQuickShapePathPrivate::DirtyFillGradient)
renderer->setFillGradient(i, p->fillGradient());
+ if (dirty & QQuickShapePathPrivate::DirtyFillTransform)
+ renderer->setFillTransform(i, QQuickShapePathPrivate::get(p)->sfp.fillTransform);
+ if (dirty & QQuickShapePathPrivate::DirtyFillItem) {
+ if (p->fillItem() == nullptr) {
+ renderer->setFillTextureProvider(i, nullptr);
+ } else if (p->fillItem()->isTextureProvider()) {
+ renderer->setFillTextureProvider(i, p->fillItem());
+ } else {
+ renderer->setFillTextureProvider(i, nullptr);
+ qWarning() << "QQuickShape: Fill item is not texture provider";
+ }
+ }
dirty = 0;
}
diff --git a/src/quickshapes/qquickshape_p.h b/src/quickshapes/qquickshape_p.h
index effbce1f8e..3ed4927c2d 100644
--- a/src/quickshapes/qquickshape_p.h
+++ b/src/quickshapes/qquickshape_p.h
@@ -197,6 +197,8 @@ class Q_QUICKSHAPES_EXPORT QQuickShapePath : public QQuickPath
Q_PROPERTY(QQuickShapeGradient *fillGradient READ fillGradient WRITE setFillGradient RESET resetFillGradient)
Q_PROPERTY(QSizeF scale READ scale WRITE setScale NOTIFY scaleChanged REVISION(1, 14))
Q_PROPERTY(PathHints pathHints READ pathHints WRITE setPathHints NOTIFY pathHintsChanged REVISION(6, 7) FINAL)
+ Q_PROPERTY(QMatrix4x4 fillTransform READ fillTransform WRITE setFillTransform NOTIFY fillTransformChanged REVISION(6, 8) FINAL)
+ Q_PROPERTY(QQuickItem *fillItem READ fillItem WRITE setFillItem NOTIFY fillItemChanged REVISION(6, 8) FINAL)
QML_NAMED_ELEMENT(ShapePath)
QML_ADDED_IN_VERSION(1, 0)
@@ -279,6 +281,12 @@ public:
PathHints pathHints() const;
void setPathHints(PathHints newPathHints);
+ QMatrix4x4 fillTransform() const;
+ void setFillTransform(const QMatrix4x4 &matrix);
+
+ QQuickItem *fillItem() const;
+ void setFillItem(QQuickItem *newFillItem);
+
Q_SIGNALS:
void shapePathChanged();
void strokeColorChanged();
@@ -293,11 +301,14 @@ Q_SIGNALS:
void dashPatternChanged();
Q_REVISION(6, 7) void pathHintsChanged();
+ Q_REVISION(6, 8) void fillTransformChanged();
+ Q_REVISION(6, 8) void fillItemChanged();
private:
Q_DISABLE_COPY(QQuickShapePath)
Q_DECLARE_PRIVATE(QQuickShapePath)
Q_PRIVATE_SLOT(d_func(), void _q_fillGradientChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_fillItemDestroyed())
};
class Q_QUICKSHAPES_EXPORT QQuickShape : public QQuickItem
diff --git a/src/quickshapes/qquickshape_p_p.h b/src/quickshapes/qquickshape_p_p.h
index a36aa1e27f..cce52d876f 100644
--- a/src/quickshapes/qquickshape_p_p.h
+++ b/src/quickshapes/qquickshape_p_p.h
@@ -18,6 +18,7 @@
#include <QtQuickShapes/private/qquickshapesglobal_p.h>
#include <QtQuickShapes/private/qquickshape_p.h>
#include <private/qquickitem_p.h>
+#include <private/qsgtransform_p.h>
#include <QPainterPath>
#include <QColor>
#include <QBrush>
@@ -56,7 +57,10 @@ public:
virtual void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
qreal dashOffset, const QVector<qreal> &dashPattern) = 0;
virtual void setFillGradient(int index, QQuickShapeGradient *gradient) = 0;
+ virtual void setFillTextureProvider(int index, QQuickItem *textureProviderItem) = 0;
+ virtual void setFillTransform(int index, const QSGTransform &transform) = 0;
virtual void setTriangulationScale(qreal) { }
+ virtual void handleSceneChange(QQuickWindow *window) = 0;
// Render thread, with gui blocked
virtual void updateNode() = 0;
@@ -79,6 +83,8 @@ struct QQuickShapeStrokeFillParams
qreal dashOffset;
QVector<qreal> dashPattern;
QQuickShapeGradient *fillGradient;
+ QSGTransform fillTransform;
+ QQuickItem *fillItem;
};
class Q_QUICKSHAPES_EXPORT QQuickShapePathPrivate : public QQuickPathPrivate
@@ -95,14 +101,19 @@ public:
DirtyStyle = 0x20,
DirtyDash = 0x40,
DirtyFillGradient = 0x80,
+ DirtyFillTransform = 0x100,
+ DirtyFillItem = 0x200,
- DirtyAll = 0xFF
+ DirtyAll = 0x3FF
};
QQuickShapePathPrivate();
void _q_pathChanged();
void _q_fillGradientChanged();
+ void _q_fillItemDestroyed();
+
+ void handleSceneChange();
static QQuickShapePathPrivate *get(QQuickShapePath *p) { return p->d_func(); }
@@ -126,6 +137,7 @@ public:
void _q_shapePathChanged();
void setStatus(QQuickShape::Status newStatus);
+ void handleSceneChange(QQuickWindow *w);
static QQuickShapePrivate *get(QQuickShape *item) { return item->d_func(); }
diff --git a/src/quickshapes/qquickshapecurverenderer.cpp b/src/quickshapes/qquickshapecurverenderer.cpp
index 856d83fdac..6c16df449b 100644
--- a/src/quickshapes/qquickshapecurverenderer.cpp
+++ b/src/quickshapes/qquickshapecurverenderer.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qquickshapecurverenderer_p.h"
@@ -233,6 +233,7 @@ void QQuickShapeCurveRenderer::setStrokeStyle(int index,
void QQuickShapeCurveRenderer::setFillGradient(int index, QQuickShapeGradient *gradient)
{
PathData &pd(m_paths[index]);
+ const bool wasVisible = pd.isFillVisible();
pd.gradientType = QGradient::NoGradient;
if (QQuickShapeLinearGradient *g = qobject_cast<QQuickShapeLinearGradient *>(gradient)) {
pd.gradientType = QGradient::LinearGradient;
@@ -250,8 +251,7 @@ void QQuickShapeCurveRenderer::setFillGradient(int index, QQuickShapeGradient *g
pd.gradientType = QGradient::ConicalGradient;
pd.gradient.a = QPointF(g->centerX(), g->centerY());
pd.gradient.v0 = g->angle();
- } else
- if (gradient != nullptr) {
+ } else if (gradient != nullptr) {
static bool warned = false;
if (!warned) {
warned = true;
@@ -264,7 +264,38 @@ void QQuickShapeCurveRenderer::setFillGradient(int index, QQuickShapeGradient *g
pd.gradient.spread = QGradient::Spread(gradient->spread());
}
- pd.m_dirty |= FillDirty;
+ pd.m_dirty |= (pd.isFillVisible() != wasVisible) ? FillDirty : UniformsDirty;
+}
+
+void QQuickShapeCurveRenderer::setFillTransform(int index, const QSGTransform &transform)
+{
+ auto &pathData = m_paths[index];
+ pathData.fillTransform = transform;
+ pathData.m_dirty |= UniformsDirty;
+}
+
+void QQuickShapeCurveRenderer::setFillTextureProvider(int index, QQuickItem *textureProviderItem)
+{
+ auto &pathData = m_paths[index];
+ const bool wasVisible = pathData.isFillVisible();
+ if (pathData.fillTextureProviderItem != nullptr)
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->derefWindow();
+ pathData.fillTextureProviderItem = textureProviderItem;
+ if (pathData.fillTextureProviderItem != nullptr)
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->refWindow(m_item->window());
+ pathData.m_dirty |= (pathData.isFillVisible() != wasVisible) ? FillDirty : UniformsDirty;
+}
+
+void QQuickShapeCurveRenderer::handleSceneChange(QQuickWindow *window)
+{
+ for (auto &pathData : m_paths) {
+ if (pathData.fillTextureProviderItem != nullptr) {
+ if (window == nullptr)
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->derefWindow();
+ else
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->refWindow(window);
+ }
+ }
}
void QQuickShapeCurveRenderer::setAsyncCallback(void (*callback)(void *), void *data)
@@ -357,8 +388,16 @@ void QQuickShapeCurveRenderer::updateNode()
return;
auto updateUniforms = [](const PathData &pathData) {
- for (auto &pathNode : std::as_const(pathData.fillNodes))
- pathNode->setColor(pathData.fillColor);
+ for (auto &pathNode : std::as_const(pathData.fillNodes)) {
+ QSGCurveFillNode *fillNode = static_cast<QSGCurveFillNode *>(pathNode);
+ fillNode->setColor(pathData.fillColor);
+ fillNode->setGradientType(pathData.gradientType);
+ fillNode->setFillGradient(pathData.gradient);
+ fillNode->setFillTransform(pathData.fillTransform);
+ fillNode->setFillTextureProvider(pathData.fillTextureProviderItem != nullptr
+ ? pathData.fillTextureProviderItem->textureProvider()
+ : nullptr);
+ }
for (auto &strokeNode : std::as_const(pathData.strokeNodes))
strokeNode->setColor(pathData.pen.color());
};
@@ -451,8 +490,8 @@ void QQuickShapeCurveRenderer::processPath(PathData *pathData)
if (doOverlapSolving)
QSGCurveProcessor::solveOverlaps(pathData->fillPath);
}
- pathData->fillNodes = addFillNodes(*pathData);
- dirtyFlags |= StrokeDirty;
+ pathData->fillNodes = addFillNodes(pathData->fillPath);
+ dirtyFlags |= (StrokeDirty | UniformsDirty);
}
}
@@ -472,17 +511,15 @@ void QQuickShapeCurveRenderer::processPath(PathData *pathData)
}
}
-QQuickShapeCurveRenderer::NodeList QQuickShapeCurveRenderer::addFillNodes(const PathData &pathData)
+QQuickShapeCurveRenderer::NodeList QQuickShapeCurveRenderer::addFillNodes(const QQuadPath &path)
{
auto *node = new QSGCurveFillNode;
- node->setGradientType(pathData.gradientType);
- const qsizetype approxDataCount = 20 * pathData.fillPath.elementCount();
+ const qsizetype approxDataCount = 20 * path.elementCount();
node->reserve(approxDataCount);
NodeList ret;
- const QColor &color = pathData.fillColor;
QPainterPath internalHull;
- internalHull.setFillRule(pathData.fillPath.fillRule());
+ internalHull.setFillRule(path.fillRule());
bool visualizeDebug = debugVisualization() & DebugCurves;
const float dbg = visualizeDebug ? 0.5f : 0.0f;
@@ -491,8 +528,8 @@ QQuickShapeCurveRenderer::NodeList QQuickShapeCurveRenderer::addFillNodes(const
QVector<QQuickShapeWireFrameNode::WireFrameVertex> wfVertices;
wfVertices.reserve(approxDataCount);
- QSGCurveProcessor::processFill(pathData.fillPath,
- pathData.fillRule,
+ QSGCurveProcessor::processFill(path,
+ path.fillRule(),
[&wfVertices, &node](const std::array<QVector2D, 3> &v,
const std::array<QVector2D, 3> &n,
QSGCurveProcessor::uvForPointCallback uvForPoint)
@@ -506,9 +543,6 @@ QQuickShapeCurveRenderer::NodeList QQuickShapeCurveRenderer::addFillNodes(const
QVector<quint32> indices = node->uncookedIndexes();
if (indices.size() > 0) {
- node->setColor(color);
- node->setFillGradient(pathData.gradient);
-
node->cookGeometry();
ret.append(node);
}
diff --git a/src/quickshapes/qquickshapecurverenderer_p.h b/src/quickshapes/qquickshapecurverenderer_p.h
index f2b10fb44c..a664b5efb4 100644
--- a/src/quickshapes/qquickshapecurverenderer_p.h
+++ b/src/quickshapes/qquickshapecurverenderer_p.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQUICKSHAPECURVERENDERER_P_H
@@ -55,9 +55,12 @@ public:
void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
qreal dashOffset, const QVector<qreal> &dashPattern) override;
void setFillGradient(int index, QQuickShapeGradient *gradient) override;
+ void setFillTextureProvider(int index, QQuickItem *textureProviderItem) override;
+ void setFillTransform(int index, const QSGTransform &transform) override;
void endSync(bool async) override;
void setAsyncCallback(void (*)(void *), void *) override;
Flags flags() const override { return SupportsAsync; }
+ void handleSceneChange(QQuickWindow *window) override;
void updateNode() override;
@@ -85,7 +88,12 @@ public:
private:
struct PathData {
- bool isFillVisible() const { return fillColor.alpha() > 0 || gradientType != QGradient::NoGradient; }
+ bool isFillVisible() const
+ {
+ return gradientType != QGradient::NoGradient
+ || fillTextureProviderItem != nullptr
+ || fillColor.alpha() > 0;
+ }
bool isStrokeVisible() const
{
@@ -94,6 +102,7 @@ private:
QGradient::Type gradientType = QGradient::NoGradient;
QSGGradientCache::GradientDesc gradient;
+ QSGTransform fillTransform;
QColor fillColor;
Qt::FillRule fillRule = Qt::OddEvenFill;
QPen pen;
@@ -110,13 +119,14 @@ private:
NodeList strokeNodes;
QQuickShapeCurveRunnable *currentRunner = nullptr;
+ QQuickItem *fillTextureProviderItem = nullptr;
};
void createRunner(PathData *pathData);
void maybeUpdateAsyncItem();
static void processPath(PathData *pathData);
- static NodeList addFillNodes(const PathData &pathData);
+ static NodeList addFillNodes(const QQuadPath &path);
static NodeList addTriangulatingStrokerNodes(const PathData &pathData);
static NodeList addCurveStrokeNodes(const PathData &pathData);
diff --git a/src/quickshapes/qquickshapegenericrenderer.cpp b/src/quickshapes/qquickshapegenericrenderer.cpp
index a18479f776..34c7fa96a0 100644
--- a/src/quickshapes/qquickshapegenericrenderer.cpp
+++ b/src/quickshapes/qquickshapegenericrenderer.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qquickshapegenericrenderer_p.h"
@@ -6,6 +6,8 @@
#include <QtGui/private/qtriangulatingstroker_p.h>
#include <rhi/qrhi.h>
#include <QSGVertexColorMaterial>
+#include <QSGTextureProvider>
+#include <private/qsgplaintexture_p.h>
#include <QtQuick/private/qsggradientcache_p.h>
@@ -42,6 +44,7 @@ QQuickShapeGenericStrokeFillNode::QQuickShapeGenericStrokeFillNode(QQuickWindow
: m_material(nullptr)
{
setFlag(QSGNode::OwnsGeometry, true);
+ setFlag(QSGNode::UsePreprocess, true);
setGeometry(new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0, 0));
activateMaterial(window, MatSolidColor);
#ifdef QSG_RUNTIME_DESCRIPTION
@@ -66,6 +69,9 @@ void QQuickShapeGenericStrokeFillNode::activateMaterial(QQuickWindow *window, Ma
case MatConicalGradient:
m_material.reset(QQuickShapeGenericMaterialFactory::createConicalGradient(window, this));
break;
+ case MatTextureFill:
+ m_material.reset(QQuickShapeGenericMaterialFactory::createTextureFill(window, this));
+ break;
default:
qWarning("Unknown material %d", m);
return;
@@ -75,6 +81,25 @@ void QQuickShapeGenericStrokeFillNode::activateMaterial(QQuickWindow *window, Ma
setMaterial(m_material.data());
}
+void QQuickShapeGenericStrokeFillNode::preprocess()
+{
+ if (m_fillTextureProvider != nullptr) {
+ if (QSGDynamicTexture *texture = qobject_cast<QSGDynamicTexture *>(m_fillTextureProvider->texture()))
+ texture->updateTexture();
+ }
+}
+
+void QQuickShapeGenericStrokeFillNode::handleTextureChanged()
+{
+ markDirty(QSGNode::DirtyMaterial);
+}
+
+void QQuickShapeGenericStrokeFillNode::handleTextureProviderDestroyed()
+{
+ m_fillTextureProvider = nullptr;
+ markDirty(QSGNode::DirtyMaterial);
+}
+
QQuickShapeGenericRenderer::~QQuickShapeGenericRenderer()
{
for (ShapePathData &d : m_sp) {
@@ -202,6 +227,39 @@ void QQuickShapeGenericRenderer::setFillGradient(int index, QQuickShapeGradient
d.syncDirty |= DirtyFillGradient;
}
+void QQuickShapeGenericRenderer::setFillTextureProvider(int index, QQuickItem *textureProviderItem)
+{
+ ShapePathData &d(m_sp[index]);
+ if ((d.fillTextureProviderItem == nullptr) != (textureProviderItem == nullptr))
+ d.syncDirty |= DirtyFillGeom;
+ if (d.fillTextureProviderItem != nullptr)
+ QQuickItemPrivate::get(d.fillTextureProviderItem)->derefWindow();
+ d.fillTextureProviderItem = textureProviderItem;
+ if (d.fillTextureProviderItem != nullptr)
+ QQuickItemPrivate::get(d.fillTextureProviderItem)->refWindow(m_item->window());
+ d.syncDirty |= DirtyFillTexture;
+}
+
+void QQuickShapeGenericRenderer::handleSceneChange(QQuickWindow *window)
+{
+ for (auto &pathData : m_sp) {
+ if (pathData.fillTextureProviderItem != nullptr) {
+ if (window == nullptr)
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->derefWindow();
+ else
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->refWindow(window);
+ }
+ }
+}
+
+
+void QQuickShapeGenericRenderer::setFillTransform(int index, const QSGTransform &transform)
+{
+ ShapePathData &d(m_sp[index]);
+ d.fillTransform = transform;
+ d.syncDirty |= DirtyFillTransform;
+}
+
void QQuickShapeGenericRenderer::setTriangulationScale(qreal scale)
{
// No dirty, this is called at the start of every sync. Just store the value.
@@ -491,7 +549,7 @@ void QQuickShapeGenericRenderer::updateNode()
QQuickShapeGenericNode *node = *nodePtr;
if (m_accDirty & DirtyList)
- d.effectiveDirty |= DirtyFillGeom | DirtyStrokeGeom | DirtyColor | DirtyFillGradient;
+ d.effectiveDirty |= DirtyFillGeom | DirtyStrokeGeom | DirtyColor | DirtyFillGradient | DirtyFillTransform | DirtyFillTexture;
if (!d.effectiveDirty) {
prevNode = node;
@@ -545,13 +603,43 @@ void QQuickShapeGenericRenderer::updateShadowDataInNode(ShapePathData *d, QQuick
if (d->effectiveDirty & DirtyFillGradient)
n->m_fillGradient = d->fillGradient;
}
+ if (d->effectiveDirty & DirtyFillTexture) {
+ bool needsUpdate = d->fillTextureProviderItem == nullptr && n->m_fillTextureProvider != nullptr;
+ if (!needsUpdate
+ && d->fillTextureProviderItem != nullptr
+ && n->m_fillTextureProvider != d->fillTextureProviderItem->textureProvider()) {
+ needsUpdate = true;
+ }
+
+ if (needsUpdate) {
+ if (n->m_fillTextureProvider != nullptr) {
+ QObject::disconnect(n->m_fillTextureProvider, &QSGTextureProvider::textureChanged,
+ n, &QQuickShapeGenericStrokeFillNode::handleTextureChanged);
+ QObject::disconnect(n->m_fillTextureProvider, &QSGTextureProvider::destroyed,
+ n, &QQuickShapeGenericStrokeFillNode::handleTextureProviderDestroyed);
+ }
+
+ n->m_fillTextureProvider = d->fillTextureProviderItem == nullptr
+ ? nullptr
+ : d->fillTextureProviderItem->textureProvider();
+
+ if (n->m_fillTextureProvider != nullptr) {
+ QObject::connect(n->m_fillTextureProvider, &QSGTextureProvider::textureChanged,
+ n, &QQuickShapeGenericStrokeFillNode::handleTextureChanged);
+ QObject::connect(n->m_fillTextureProvider, &QSGTextureProvider::destroyed,
+ n, &QQuickShapeGenericStrokeFillNode::handleTextureProviderDestroyed);
+ }
+ }
+ }
+ if (d->effectiveDirty & DirtyFillTransform)
+ n->m_fillTransform = d->fillTransform;
}
void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGenericNode *node)
{
if (!node->m_fillNode)
return;
- if (!(d->effectiveDirty & (DirtyFillGeom | DirtyColor | DirtyFillGradient)))
+ if (!(d->effectiveDirty & (DirtyFillGeom | DirtyColor | DirtyFillGradient | DirtyFillTransform | DirtyFillTexture)))
return;
// Make a copy of the data that will be accessed by the material on
@@ -584,17 +672,21 @@ void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGen
Q_UNREACHABLE_RETURN();
}
n->activateMaterial(m_item->window(), gradMat);
- if (d->effectiveDirty & DirtyFillGradient) {
+ if (d->effectiveDirty & (DirtyFillGradient | DirtyFillTransform)) {
// Gradients are implemented via a texture-based material.
n->markDirty(QSGNode::DirtyMaterial);
- // stop here if only the gradient changed; no need to touch the geometry
+ // stop here if only the gradient or filltransform changed; no need to touch the geometry
if (!(d->effectiveDirty & DirtyFillGeom))
return;
}
+ } else if (d->fillTextureProviderItem != nullptr) {
+ n->activateMaterial(m_item->window(), QQuickShapeGenericStrokeFillNode::MatTextureFill);
+ if (d->effectiveDirty & DirtyFillTexture)
+ n->markDirty(QSGNode::DirtyMaterial);
} else {
n->activateMaterial(m_item->window(), QQuickShapeGenericStrokeFillNode::MatSolidColor);
// fast path for updating only color values when no change in vertex positions
- if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyFillGeom)) {
+ if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyFillGeom) && d->fillTextureProviderItem == nullptr) {
ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData());
for (int i = 0; i < g->vertexCount(); ++i)
vdst[i].set(vdst[i].x, vdst[i].y, d->fillColor);
@@ -613,6 +705,7 @@ void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGen
g->allocate(d->fillVertices.size(), indexCount);
}
g->setDrawingMode(QSGGeometry::DrawTriangles);
+
memcpy(g->vertexData(), d->fillVertices.constData(), g->vertexCount() * g->sizeOfVertex());
memcpy(g->indexData(), d->fillIndices.constData(), g->indexCount() * g->sizeOfIndex());
@@ -703,6 +796,18 @@ QSGMaterial *QQuickShapeGenericMaterialFactory::createConicalGradient(QQuickWind
return nullptr;
}
+QSGMaterial *QQuickShapeGenericMaterialFactory::createTextureFill(QQuickWindow *window,
+ QQuickShapeGenericStrokeFillNode *node)
+{
+ QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
+
+ if (api == QSGRendererInterface::OpenGL || QSGRendererInterface::isApiRhiBased(api))
+ return new QQuickShapeTextureFillMaterial(node);
+
+ qWarning("Texture fill material: Unsupported graphics API %d", api);
+ return nullptr;
+}
+
QQuickShapeLinearGradientRhiShader::QQuickShapeLinearGradientRhiShader(int viewCount)
{
setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/lineargradient.vert.qsb"), viewCount);
@@ -716,7 +821,7 @@ bool QQuickShapeLinearGradientRhiShader::updateUniformData(RenderState &state,
QQuickShapeLinearGradientMaterial *m = static_cast<QQuickShapeLinearGradientMaterial *>(newMaterial);
bool changed = false;
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 84);
+ Q_ASSERT(buf->size() >= 84 + 64);
const int shaderMatrixCount = newMaterial->viewCount();
const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
@@ -730,22 +835,28 @@ bool QQuickShapeLinearGradientRhiShader::updateUniformData(RenderState &state,
QQuickShapeGenericStrokeFillNode *node = m->node();
+ if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
+ memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
+ m_fillTransform = node->m_fillTransform;
+ changed = true;
+ }
+
if (!oldMaterial || m_gradA.x() != node->m_fillGradient.a.x() || m_gradA.y() != node->m_fillGradient.a.y()) {
m_gradA = QVector2D(node->m_fillGradient.a.x(), node->m_fillGradient.a.y());
Q_ASSERT(sizeof(m_gradA) == 8);
- memcpy(buf->data() + 64 * shaderMatrixCount, &m_gradA, 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_gradA, 8);
changed = true;
}
if (!oldMaterial || m_gradB.x() != node->m_fillGradient.b.x() || m_gradB.y() != node->m_fillGradient.b.y()) {
m_gradB = QVector2D(node->m_fillGradient.b.x(), node->m_fillGradient.b.y());
- memcpy(buf->data() + 64 * shaderMatrixCount + 8, &m_gradB, 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_gradB, 8);
changed = true;
}
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
- memcpy(buf->data() + 64 * shaderMatrixCount + 8 + 8, &opacity, 4);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8, &opacity, 4);
changed = true;
}
@@ -808,6 +919,9 @@ int QQuickShapeLinearGradientMaterial::compare(const QSGMaterial *other) const
return d;
}
+ if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
+ return d;
+
return 0;
}
@@ -830,7 +944,7 @@ bool QQuickShapeRadialGradientRhiShader::updateUniformData(RenderState &state,
QQuickShapeRadialGradientMaterial *m = static_cast<QQuickShapeRadialGradientMaterial *>(newMaterial);
bool changed = false;
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 92);
+ Q_ASSERT(buf->size() >= 92 + 64);
const int shaderMatrixCount = newMaterial->viewCount();
const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
@@ -844,6 +958,12 @@ bool QQuickShapeRadialGradientRhiShader::updateUniformData(RenderState &state,
QQuickShapeGenericStrokeFillNode *node = m->node();
+ if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
+ memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
+ m_fillTransform = node->m_fillTransform;
+ changed = true;
+ }
+
const QPointF centerPoint = node->m_fillGradient.a;
const QPointF focalPoint = node->m_fillGradient.b;
const QPointF focalToCenter = centerPoint - focalPoint;
@@ -853,32 +973,32 @@ bool QQuickShapeRadialGradientRhiShader::updateUniformData(RenderState &state,
if (!oldMaterial || m_focalPoint.x() != focalPoint.x() || m_focalPoint.y() != focalPoint.y()) {
m_focalPoint = QVector2D(focalPoint.x(), focalPoint.y());
Q_ASSERT(sizeof(m_focalPoint) == 8);
- memcpy(buf->data() + 64 * shaderMatrixCount, &m_focalPoint, 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_focalPoint, 8);
changed = true;
}
if (!oldMaterial || m_focalToCenter.x() != focalToCenter.x() || m_focalToCenter.y() != focalToCenter.y()) {
m_focalToCenter = QVector2D(focalToCenter.x(), focalToCenter.y());
Q_ASSERT(sizeof(m_focalToCenter) == 8);
- memcpy(buf->data() + 64 * shaderMatrixCount + 8, &m_focalToCenter, 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_focalToCenter, 8);
changed = true;
}
if (!oldMaterial || m_centerRadius != centerRadius) {
m_centerRadius = centerRadius;
- memcpy(buf->data() + 64 * shaderMatrixCount + 8 + 8, &m_centerRadius, 4);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8, &m_centerRadius, 4);
changed = true;
}
if (!oldMaterial || m_focalRadius != focalRadius) {
m_focalRadius = focalRadius;
- memcpy(buf->data() + 64 * shaderMatrixCount + 8 + 8 + 4, &m_focalRadius, 4);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8 + 4, &m_focalRadius, 4);
changed = true;
}
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
- memcpy(buf->data() + 64 * shaderMatrixCount + 8 + 8 + 4 + 4, &opacity, 4);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8 + 4 + 4, &opacity, 4);
changed = true;
}
@@ -946,6 +1066,9 @@ int QQuickShapeRadialGradientMaterial::compare(const QSGMaterial *other) const
return d;
}
+ if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
+ return d;
+
return 0;
}
@@ -968,7 +1091,7 @@ bool QQuickShapeConicalGradientRhiShader::updateUniformData(RenderState &state,
QQuickShapeConicalGradientMaterial *m = static_cast<QQuickShapeConicalGradientMaterial *>(newMaterial);
bool changed = false;
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 80);
+ Q_ASSERT(buf->size() >= 80 + 64);
const int shaderMatrixCount = newMaterial->viewCount();
const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
@@ -982,25 +1105,31 @@ bool QQuickShapeConicalGradientRhiShader::updateUniformData(RenderState &state,
QQuickShapeGenericStrokeFillNode *node = m->node();
+ if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
+ memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
+ m_fillTransform = node->m_fillTransform;
+ changed = true;
+ }
+
const QPointF centerPoint = node->m_fillGradient.a;
const float angle = -qDegreesToRadians(node->m_fillGradient.v0);
if (!oldMaterial || m_centerPoint.x() != centerPoint.x() || m_centerPoint.y() != centerPoint.y()) {
m_centerPoint = QVector2D(centerPoint.x(), centerPoint.y());
Q_ASSERT(sizeof(m_centerPoint) == 8);
- memcpy(buf->data() + 64 * shaderMatrixCount, &m_centerPoint, 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_centerPoint, 8);
changed = true;
}
if (!oldMaterial || m_angle != angle) {
m_angle = angle;
- memcpy(buf->data() + 64 * shaderMatrixCount + 8, &m_angle, 4);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_angle, 4);
changed = true;
}
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
- memcpy(buf->data() + 64 * shaderMatrixCount + 8 + 4, &opacity, 4);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 4, &opacity, 4);
changed = true;
}
@@ -1059,6 +1188,9 @@ int QQuickShapeConicalGradientMaterial::compare(const QSGMaterial *other) const
return d;
}
+ if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
+ return d;
+
return 0;
}
@@ -1068,6 +1200,139 @@ QSGMaterialShader *QQuickShapeConicalGradientMaterial::createShader(QSGRendererI
return new QQuickShapeConicalGradientRhiShader(viewCount());
}
+QQuickShapeTextureFillRhiShader::QQuickShapeTextureFillRhiShader(int viewCount)
+{
+ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/texturefill.vert.qsb"), viewCount);
+ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/texturefill.frag.qsb"), viewCount);
+}
+
+bool QQuickShapeTextureFillRhiShader::updateUniformData(RenderState &state,
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
+{
+ Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
+ QQuickShapeTextureFillMaterial *m = static_cast<QQuickShapeTextureFillMaterial *>(newMaterial);
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+ const int shaderMatrixCount = newMaterial->viewCount();
+ const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
+ Q_ASSERT(buf->size() >= 64 * shaderMatrixCount + 64 + 8 + 4);
+
+ if (state.isMatrixDirty()) {
+ for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
+ const QMatrix4x4 m = state.combinedMatrix();
+ memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
+ changed = true;
+ }
+ }
+
+ QQuickShapeGenericStrokeFillNode *node = m->node();
+
+ if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
+ memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
+ m_fillTransform = node->m_fillTransform;
+ changed = true;
+ }
+
+ const QSizeF boundsSize = node->m_fillTextureProvider != nullptr && node->m_fillTextureProvider->texture() != nullptr
+ ? node->m_fillTextureProvider->texture()->textureSize()
+ : QSizeF(0, 0);
+
+
+ const QVector2D boundsVector(boundsSize.width() / state.devicePixelRatio(),
+ boundsSize.height() / state.devicePixelRatio());
+ if (!oldMaterial || m_boundsSize != boundsVector) {
+ m_boundsSize = boundsVector;
+ Q_ASSERT(sizeof(m_boundsSize) == 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_boundsSize, 8);
+ changed = true;
+ }
+
+ if (state.isOpacityDirty()) {
+ const float opacity = state.opacity();
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &opacity, 4);
+ changed = true;
+ }
+
+ return changed;
+}
+
+void QQuickShapeTextureFillRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *)
+{
+ if (binding != 1)
+ return;
+
+ QQuickShapeTextureFillMaterial *m = static_cast<QQuickShapeTextureFillMaterial *>(newMaterial);
+ QQuickShapeGenericStrokeFillNode *node = m->node();
+ if (node->m_fillTextureProvider != nullptr) {
+ QSGTexture *providedTexture = node->m_fillTextureProvider->texture();
+ if (providedTexture != nullptr) {
+ if (providedTexture->isAtlasTexture()) {
+ // Create a non-atlas copy to make texture coordinate wrapping work. This
+ // texture copy is owned by the QSGTexture so memory is managed with the original
+ // texture provider.
+ QSGTexture *newTexture = providedTexture->removedFromAtlas(state.resourceUpdateBatch());
+ if (newTexture != nullptr)
+ providedTexture = newTexture;
+ }
+
+ providedTexture->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+ *texture = providedTexture;
+ return;
+ }
+ }
+
+ if (m->dummyTexture() == nullptr) {
+ QSGPlainTexture *dummyTexture = new QSGPlainTexture;
+ dummyTexture->setFiltering(QSGTexture::Nearest);
+ dummyTexture->setHorizontalWrapMode(QSGTexture::Repeat);
+ dummyTexture->setVerticalWrapMode(QSGTexture::Repeat);
+ QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
+ img.fill(0);
+ dummyTexture->setImage(img);
+ dummyTexture->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+
+ m->setDummyTexture(dummyTexture);
+ }
+
+ *texture = m->dummyTexture();
+}
+
+QQuickShapeTextureFillMaterial::~QQuickShapeTextureFillMaterial()
+{
+ delete m_dummyTexture;
+}
+
+QSGMaterialType *QQuickShapeTextureFillMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+int QQuickShapeTextureFillMaterial::compare(const QSGMaterial *other) const
+{
+ Q_ASSERT(other && type() == other->type());
+ const QQuickShapeTextureFillMaterial *m = static_cast<const QQuickShapeTextureFillMaterial *>(other);
+
+ QQuickShapeGenericStrokeFillNode *a = node();
+ QQuickShapeGenericStrokeFillNode *b = m->node();
+ Q_ASSERT(a && b);
+ if (a == b)
+ return 0;
+
+ if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
+ return d;
+
+ const qintptr diff = qintptr(a->m_fillTextureProvider) - qintptr(b->m_fillTextureProvider);
+ return diff < 0 ? -1 : (diff > 0 ? 1 : 0);
+}
+
+QSGMaterialShader *QQuickShapeTextureFillMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
+{
+ Q_UNUSED(renderMode);
+ return new QQuickShapeTextureFillRhiShader(viewCount());
+}
+
QT_END_NAMESPACE
#include "moc_qquickshapegenericrenderer_p.cpp"
diff --git a/src/quickshapes/qquickshapegenericrenderer_p.h b/src/quickshapes/qquickshapegenericrenderer_p.h
index 6877b674e0..7f5ce81da0 100644
--- a/src/quickshapes/qquickshapegenericrenderer_p.h
+++ b/src/quickshapes/qquickshapegenericrenderer_p.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQUICKSHAPEGENERICRENDERER_P_H
@@ -40,7 +40,9 @@ public:
DirtyStrokeGeom = 0x02,
DirtyColor = 0x04,
DirtyFillGradient = 0x08,
- DirtyList = 0x10 // only for accDirty
+ DirtyFillTransform = 0x10,
+ DirtyFillTexture = 0x20,
+ DirtyList = 0x40 // only for accDirty
};
QQuickShapeGenericRenderer(QQuickItem *item)
@@ -64,10 +66,13 @@ public:
void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
qreal dashOffset, const QVector<qreal> &dashPattern) override;
void setFillGradient(int index, QQuickShapeGradient *gradient) override;
+ void setFillTextureProvider(int index, QQuickItem *textureProviderItem) override;
+ void setFillTransform(int index, const QSGTransform &transform) override;
void setTriangulationScale(qreal scale) override;
void endSync(bool async) override;
void setAsyncCallback(void (*)(void *), void *) override;
Flags flags() const override { return SupportsAsync; }
+ void handleSceneChange(QQuickWindow *window) override;
void updateNode() override;
@@ -75,6 +80,7 @@ public:
struct Color4ub { unsigned char r, g, b, a; };
typedef QVector<QSGGeometry::ColoredPoint2D> VertexContainerType;
+ typedef QVector<QSGGeometry::TexturedPoint2D> TexturedVertexContainerType;
typedef QVector<quint32> IndexContainerType;
static void triangulateFill(const QPainterPath &path,
@@ -103,6 +109,8 @@ private:
QPainterPath path;
FillGradientType fillGradientActive;
QSGGradientCache::GradientDesc fillGradient;
+ QQuickItem *fillTextureProviderItem = nullptr;
+ QSGTransform fillTransform;
VertexContainerType fillVertices;
IndexContainerType fillIndices;
QSGGeometry::Type indexType;
@@ -174,8 +182,9 @@ Q_SIGNALS:
void done(QQuickShapeStrokeRunnable *self);
};
-class QQuickShapeGenericStrokeFillNode : public QSGGeometryNode
+class QQuickShapeGenericStrokeFillNode : public QObject, public QSGGeometryNode
{
+ Q_OBJECT
public:
QQuickShapeGenericStrokeFillNode(QQuickWindow *window);
@@ -183,13 +192,21 @@ public:
MatSolidColor,
MatLinearGradient,
MatRadialGradient,
- MatConicalGradient
+ MatConicalGradient,
+ MatTextureFill
};
void activateMaterial(QQuickWindow *window, Material m);
// shadow data for custom materials
QSGGradientCache::GradientDesc m_fillGradient;
+ QSGTextureProvider *m_fillTextureProvider = nullptr;
+ QSGTransform m_fillTransform;
+ void preprocess() override;
+
+private Q_SLOTS:
+ void handleTextureChanged();
+ void handleTextureProviderDestroyed();
private:
QScopedPointer<QSGMaterial> m_material;
@@ -212,6 +229,7 @@ public:
static QSGMaterial *createLinearGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
static QSGMaterial *createRadialGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
static QSGMaterial *createConicalGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
+ static QSGMaterial *createTextureFill(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
};
class QQuickShapeLinearGradientRhiShader : public QSGMaterialShader
@@ -225,6 +243,7 @@ public:
QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
private:
+ QSGTransform m_fillTransform;
QVector2D m_gradA;
QVector2D m_gradB;
};
@@ -264,6 +283,7 @@ public:
QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
private:
+ QSGTransform m_fillTransform;
QVector2D m_focalPoint;
QVector2D m_focalToCenter;
float m_centerRadius;
@@ -300,6 +320,7 @@ public:
QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
private:
+ QSGTransform m_fillTransform;
QVector2D m_centerPoint;
float m_angle;
};
@@ -323,6 +344,53 @@ private:
QQuickShapeGenericStrokeFillNode *m_node;
};
+class QQuickShapeTextureFillRhiShader : public QSGMaterialShader
+{
+public:
+ QQuickShapeTextureFillRhiShader(int viewCount);
+
+ bool updateUniformData(RenderState &state, QSGMaterial *newMaterial,
+ QSGMaterial *oldMaterial) override;
+ void updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
+
+private:
+ QSGTransform m_fillTransform;
+ QVector2D m_boundsOffset;
+ QVector2D m_boundsSize;
+};
+
+class QQuickShapeTextureFillMaterial : public QSGMaterial
+{
+public:
+ QQuickShapeTextureFillMaterial(QQuickShapeGenericStrokeFillNode *node)
+ : m_node(node)
+ {
+ setFlag(Blending | RequiresFullMatrix);
+ }
+ ~QQuickShapeTextureFillMaterial() override;
+
+ QSGMaterialType *type() const override;
+ int compare(const QSGMaterial *other) const override;
+ QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override;
+
+ QQuickShapeGenericStrokeFillNode *node() const { return m_node; }
+
+ QSGPlainTexture *dummyTexture() const
+ {
+ return m_dummyTexture;
+ }
+
+ void setDummyTexture(QSGPlainTexture *texture)
+ {
+ m_dummyTexture = texture;
+ }
+
+private:
+ QQuickShapeGenericStrokeFillNode *m_node;
+ QSGPlainTexture *m_dummyTexture = nullptr;
+};
+
QT_END_NAMESPACE
#endif // QQUICKSHAPEGENERICRENDERER_P_H
diff --git a/src/quickshapes/qquickshapesoftwarerenderer.cpp b/src/quickshapes/qquickshapesoftwarerenderer.cpp
index 60efcf1db9..f1a2e3dc67 100644
--- a/src/quickshapes/qquickshapesoftwarerenderer.cpp
+++ b/src/quickshapes/qquickshapesoftwarerenderer.cpp
@@ -138,6 +138,27 @@ void QQuickShapeSoftwareRenderer::setFillGradient(int index, QQuickShapeGradient
m_accDirty |= DirtyBrush;
}
+void QQuickShapeSoftwareRenderer::setFillTextureProvider(int index, QQuickItem *textureProviderItem)
+{
+ Q_UNUSED(index);
+ Q_UNUSED(textureProviderItem);
+}
+
+void QQuickShapeSoftwareRenderer::handleSceneChange(QQuickWindow *window)
+{
+ Q_UNUSED(window);
+ // No action needed
+}
+
+void QQuickShapeSoftwareRenderer::setFillTransform(int index, const QSGTransform &transform)
+{
+ ShapePathGuiData &d(m_sp[index]);
+ if (!(transform.isIdentity() && d.brush.transform().isIdentity())) // No need to copy if both==I
+ d.brush.setTransform(transform.matrix().toTransform());
+ d.dirty |= DirtyBrush;
+ m_accDirty |= DirtyBrush;
+}
+
void QQuickShapeSoftwareRenderer::endSync(bool)
{
}
diff --git a/src/quickshapes/qquickshapesoftwarerenderer_p.h b/src/quickshapes/qquickshapesoftwarerenderer_p.h
index d08145bb1b..94eded84e5 100644
--- a/src/quickshapes/qquickshapesoftwarerenderer_p.h
+++ b/src/quickshapes/qquickshapesoftwarerenderer_p.h
@@ -47,7 +47,10 @@ public:
void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
qreal dashOffset, const QVector<qreal> &dashPattern) override;
void setFillGradient(int index, QQuickShapeGradient *gradient) override;
+ void setFillTextureProvider(int index, QQuickItem *textureProviderItem) override;
+ void setFillTransform(int index, const QSGTransform &transform) override;
void endSync(bool async) override;
+ void handleSceneChange(QQuickWindow *window) override;
void updateNode() override;
diff --git a/src/quickshapes/shaders_ng/conicalgradient.frag b/src/quickshapes/shaders_ng/conicalgradient.frag
index 7707d55deb..59862f991a 100644
--- a/src/quickshapes/shaders_ng/conicalgradient.frag
+++ b/src/quickshapes/shaders_ng/conicalgradient.frag
@@ -14,6 +14,7 @@ layout(std140, binding = 0) uniform buf {
#else
mat4 matrix;
#endif
+ mat4 gradientMatrix;
vec2 translationPoint;
float angle;
float opacity;
diff --git a/src/quickshapes/shaders_ng/conicalgradient.vert b/src/quickshapes/shaders_ng/conicalgradient.vert
index c092198724..cdaab16842 100644
--- a/src/quickshapes/shaders_ng/conicalgradient.vert
+++ b/src/quickshapes/shaders_ng/conicalgradient.vert
@@ -11,6 +11,7 @@ layout(std140, binding = 0) uniform buf {
#else
mat4 matrix;
#endif
+ mat4 gradientMatrix;
vec2 translationPoint;
float angle;
float opacity;
@@ -18,7 +19,8 @@ layout(std140, binding = 0) uniform buf {
void main()
{
- coord = vertexCoord.xy - ubuf.translationPoint;
+ vec2 gradVertexCoord = (ubuf.gradientMatrix * vertexCoord).xy;
+ coord = gradVertexCoord - ubuf.translationPoint;
#if QSHADER_VIEW_COUNT >= 2
gl_Position = ubuf.matrix[gl_ViewIndex] * vertexCoord;
#else
diff --git a/src/quickshapes/shaders_ng/lineargradient.frag b/src/quickshapes/shaders_ng/lineargradient.frag
index 6dc4c7d5ca..b6f0dc172a 100644
--- a/src/quickshapes/shaders_ng/lineargradient.frag
+++ b/src/quickshapes/shaders_ng/lineargradient.frag
@@ -14,6 +14,7 @@ layout(std140, binding = 0) uniform buf {
#else
mat4 matrix;
#endif
+ mat4 gradientMatrix;
vec2 gradStart;
vec2 gradEnd;
float opacity;
diff --git a/src/quickshapes/shaders_ng/lineargradient.vert b/src/quickshapes/shaders_ng/lineargradient.vert
index b453739230..13168b1c0f 100644
--- a/src/quickshapes/shaders_ng/lineargradient.vert
+++ b/src/quickshapes/shaders_ng/lineargradient.vert
@@ -11,6 +11,7 @@ layout(std140, binding = 0) uniform buf {
#else
mat4 matrix;
#endif
+ mat4 gradientMatrix;
vec2 gradStart;
vec2 gradEnd;
float opacity;
@@ -18,8 +19,9 @@ layout(std140, binding = 0) uniform buf {
void main()
{
+ vec2 gradVertexCoord = (ubuf.gradientMatrix * vertexCoord).xy;
vec2 gradVec = ubuf.gradEnd - ubuf.gradStart;
- gradTabIndex = dot(gradVec, vertexCoord.xy - ubuf.gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y);
+ gradTabIndex = dot(gradVec, gradVertexCoord - ubuf.gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y);
#if QSHADER_VIEW_COUNT >= 2
gl_Position = ubuf.matrix[gl_ViewIndex] * vertexCoord;
#else
diff --git a/src/quickshapes/shaders_ng/radialgradient.frag b/src/quickshapes/shaders_ng/radialgradient.frag
index bbc68b2ce7..cfbb44ac69 100644
--- a/src/quickshapes/shaders_ng/radialgradient.frag
+++ b/src/quickshapes/shaders_ng/radialgradient.frag
@@ -14,6 +14,7 @@ layout(std140, binding = 0) uniform buf {
#else
mat4 matrix;
#endif
+ mat4 gradientMatrix;
vec2 translationPoint;
vec2 focalToCenter;
float centerRadius;
diff --git a/src/quickshapes/shaders_ng/radialgradient.vert b/src/quickshapes/shaders_ng/radialgradient.vert
index 6d3dfce745..16c8406b23 100644
--- a/src/quickshapes/shaders_ng/radialgradient.vert
+++ b/src/quickshapes/shaders_ng/radialgradient.vert
@@ -11,6 +11,7 @@ layout(std140, binding = 0) uniform buf {
#else
mat4 matrix;
#endif
+ mat4 gradientMatrix;
vec2 translationPoint;
vec2 focalToCenter;
float centerRadius;
@@ -20,7 +21,8 @@ layout(std140, binding = 0) uniform buf {
void main()
{
- coord = vertexCoord.xy - ubuf.translationPoint;
+ vec2 gradVertexCoord = (ubuf.gradientMatrix * vertexCoord).xy;
+ coord = gradVertexCoord - ubuf.translationPoint;
#if QSHADER_VIEW_COUNT >= 2
gl_Position = ubuf.matrix[gl_ViewIndex] * vertexCoord;
#else
diff --git a/src/quickshapes/shaders_ng/texturefill.frag b/src/quickshapes/shaders_ng/texturefill.frag
new file mode 100644
index 0000000000..c8a7f280f1
--- /dev/null
+++ b/src/quickshapes/shaders_ng/texturefill.frag
@@ -0,0 +1,25 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#version 440
+
+layout(location = 0) in vec2 textureCoord;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D sourceTexture;
+
+layout(std140, binding = 0) uniform buf {
+#if QSHADER_VIEW_COUNT >= 2
+ mat4 qt_Matrix[QSHADER_VIEW_COUNT];
+#else
+ mat4 qt_Matrix;
+#endif
+ mat4 fillMatrix;
+ vec2 boundsSize;
+ float qt_Opacity;
+} ubuf;
+
+void main()
+{
+ fragColor = texture(sourceTexture, textureCoord) * ubuf.qt_Opacity;
+}
diff --git a/src/quickshapes/shaders_ng/texturefill.vert b/src/quickshapes/shaders_ng/texturefill.vert
new file mode 100644
index 0000000000..c9d52469dc
--- /dev/null
+++ b/src/quickshapes/shaders_ng/texturefill.vert
@@ -0,0 +1,31 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#version 440
+
+layout(location = 0) in vec4 vertexCoord;
+layout(location = 1) in vec4 vertexColor;
+
+layout(location = 0) out vec2 textureCoord;
+
+layout(std140, binding = 0) uniform buf {
+#if QSHADER_VIEW_COUNT >= 2
+ mat4 qt_Matrix[QSHADER_VIEW_COUNT];
+#else
+ mat4 qt_Matrix;
+#endif
+ mat4 fillMatrix;
+ vec2 boundsSize;
+ float qt_Opacity;
+} ubuf;
+
+void main()
+{
+ vec2 xformed = (ubuf.fillMatrix * vertexCoord).xy;
+ textureCoord = vec2(xformed.x / ubuf.boundsSize.x, xformed.y / ubuf.boundsSize.y);
+#if QSHADER_VIEW_COUNT >= 2
+ gl_Position = ubuf.qt_Matrix[gl_ViewIndex] * vertexCoord;
+#else
+ gl_Position = ubuf.qt_Matrix * vertexCoord;
+#endif
+}
diff --git a/src/quicktemplates/CMakeLists.txt b/src/quicktemplates/CMakeLists.txt
index 441649a46a..18a128248e 100644
--- a/src/quicktemplates/CMakeLists.txt
+++ b/src/quicktemplates/CMakeLists.txt
@@ -46,6 +46,12 @@ qt_internal_add_qml_module(QuickTemplates2
qquicklabel.cpp qquicklabel_p.h
qquicklabel_p_p.h
qquickmenuseparator.cpp qquickmenuseparator_p.h
+ qquicknativeicon_p.h
+ qquicknativeicon.cpp
+ qquicknativeiconloader_p.h
+ qquicknativeiconloader.cpp
+ qquicknativemenuitem_p.h
+ qquicknativemenuitem.cpp
qquickoverlay.cpp qquickoverlay_p.h
qquickoverlay_p_p.h
qquickpage.cpp qquickpage_p.h
@@ -61,6 +67,8 @@ qt_internal_add_qml_module(QuickTemplates2
qquickpopupitem_p_p.h
qquickpopuppositioner.cpp
qquickpopuppositioner_p_p.h
+ qquickpopupwindow.cpp
+ qquickpopupwindow_p_p.h
qquickpresshandler.cpp
qquickpresshandler_p_p.h
qquickprogressbar.cpp qquickprogressbar_p.h
diff --git a/src/quicktemplates/qquickabstractbutton.cpp b/src/quicktemplates/qquickabstractbutton.cpp
index 0c1af73e55..ff2d9715c1 100644
--- a/src/quicktemplates/qquickabstractbutton.cpp
+++ b/src/quicktemplates/qquickabstractbutton.cpp
@@ -18,6 +18,8 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qpa/qplatformtheme.h>
#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuick/private/qquickaccessibleattached_p.h>
#include <QtQml/qqmllist.h>
QT_BEGIN_NAMESPACE
@@ -64,7 +66,7 @@ QT_BEGIN_NAMESPACE
This signal is emitted when the button is interactively clicked by the user via touch, mouse, or keyboard.
- \sa {Call a C++ function from QML when a Button is clicked}
+ \sa click(), animateClick(), {Call a C++ function from QML when a Button is clicked}
*/
/*!
@@ -889,6 +891,12 @@ void QQuickAbstractButton::setAction(QQuickAction *action)
setEnabled(action->isEnabled());
}
+#if QT_CONFIG(accessibility)
+ auto attached = qobject_cast<QQuickAccessibleAttached*>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(this, true));
+ Q_ASSERT(attached);
+ attached->setProxying(qobject_cast<QQuickAccessibleAttached*>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(action, true)));
+#endif
+
d->action = action;
if (oldText != text())
@@ -1051,6 +1059,8 @@ qreal QQuickAbstractButton::implicitIndicatorHeight() const
\qmlmethod void QtQuick.Controls::AbstractButton::toggle()
Toggles the checked state of the button.
+
+ \sa click(), animateClick()
*/
void QQuickAbstractButton::toggle()
{
@@ -1058,6 +1068,81 @@ void QQuickAbstractButton::toggle()
setChecked(!d->checked);
}
+/*!
+ \since Qt 6.8
+ \qmlmethod void QtQuick.Controls::AbstractButton::click()
+
+ Simulates the button being clicked with no delay between press and release.
+
+ All signals associated with a click are emitted as appropriate.
+
+ If the \l focusPolicy includes \c Qt.ClickFocus, \l activeFocus will
+ become \c true.
+
+ This function does nothing if the button is \l {enabled}{disabled}.
+
+ Calling this function again before the button is released resets
+ the release timer.
+
+ \sa animateClick(), pressed(), released(), clicked()
+*/
+void QQuickAbstractButton::click()
+{
+ Q_D(QQuickAbstractButton);
+ if (!isEnabled())
+ return;
+
+ // QQuickItemPrivate::deliverPointerEvent calls setFocusIfNeeded on real clicks,
+ // so we need to do it ourselves.
+ const bool setFocusOnPress = !QGuiApplication::styleHints()->setFocusOnTouchRelease();
+ if (setFocusOnPress && focusPolicy() & Qt::ClickFocus)
+ forceActiveFocus(Qt::MouseFocusReason);
+
+ const QPointF eventPos(d->width / 2, d->height / 2);
+ d->handlePress(eventPos, 0);
+ d->handleRelease(eventPos, 0);
+}
+
+/*!
+ \since Qt 6.8
+ \qmlmethod void QtQuick.Controls::AbstractButton::animateClick()
+
+ Simulates the button being clicked, with a 100 millisecond delay
+ between press and release, animating its visual state in the
+ process.
+
+ All signals associated with a click are emitted as appropriate.
+
+ If the \l focusPolicy includes \c Qt.ClickFocus, \l activeFocus will
+ become \c true.
+
+ This function does nothing if the button is \l {enabled}{disabled}.
+
+ Calling this function again before the button is released resets
+ the release timer.
+
+ \sa click(), pressed(), released(), clicked()
+*/
+void QQuickAbstractButton::animateClick()
+{
+ Q_D(QQuickAbstractButton);
+ if (!isEnabled())
+ return;
+
+ // See comment in click() for why we do this.
+ const bool setFocusOnPress = !QGuiApplication::styleHints()->setFocusOnTouchRelease();
+ if (setFocusOnPress && focusPolicy() & Qt::ClickFocus)
+ forceActiveFocus(Qt::MouseFocusReason);
+
+ // If the timer was already running, kill it so we can restart it.
+ if (d->animateTimer != 0)
+ killTimer(d->animateTimer);
+ else
+ d->handlePress(QPointF(d->width / 2, d->height / 2), 0);
+
+ d->animateTimer = startTimer(100);
+}
+
void QQuickAbstractButton::componentComplete()
{
Q_D(QQuickAbstractButton);
@@ -1158,6 +1243,12 @@ void QQuickAbstractButton::timerEvent(QTimerEvent *event)
emit released();
d->trigger();
emit pressed();
+ } else if (event->timerId() == d->animateTimer) {
+ const bool setFocusOnRelease = QGuiApplication::styleHints()->setFocusOnTouchRelease();
+ if (setFocusOnRelease && focusPolicy() & Qt::ClickFocus)
+ forceActiveFocus(Qt::MouseFocusReason);
+ d->handleRelease(QPointF(d->width / 2, d->height / 2), 0);
+ d->animateTimer = 0;
}
}
diff --git a/src/quicktemplates/qquickabstractbutton_p.h b/src/quicktemplates/qquickabstractbutton_p.h
index 0ac27db156..c9e7407920 100644
--- a/src/quicktemplates/qquickabstractbutton_p.h
+++ b/src/quicktemplates/qquickabstractbutton_p.h
@@ -119,6 +119,8 @@ public:
public Q_SLOTS:
void toggle();
+ Q_REVISION(6, 8) void click();
+ Q_REVISION(6, 8) void animateClick();
Q_SIGNALS:
void pressed();
diff --git a/src/quicktemplates/qquickabstractbutton_p_p.h b/src/quicktemplates/qquickabstractbutton_p_p.h
index ea9a02c99d..0d5eb65940 100644
--- a/src/quicktemplates/qquickabstractbutton_p_p.h
+++ b/src/quicktemplates/qquickabstractbutton_p_p.h
@@ -103,6 +103,7 @@ public:
int repeatTimer = 0;
int repeatDelay = AUTO_REPEAT_DELAY;
int repeatInterval = AUTO_REPEAT_INTERVAL;
+ int animateTimer = 0;
#if QT_CONFIG(shortcut)
int shortcutId = 0;
QKeySequence shortcut;
diff --git a/src/quicktemplates/qquickaction.cpp b/src/quicktemplates/qquickaction.cpp
index 3c28ae98bc..f49393bdb1 100644
--- a/src/quicktemplates/qquickaction.cpp
+++ b/src/quicktemplates/qquickaction.cpp
@@ -6,6 +6,8 @@
#include "qquickactiongroup_p.h"
#include "qquickshortcutcontext_p_p.h"
+#include <QtCore/qpointer.h>
+#include <QtCore/qloggingcategory.h>
#include <QtGui/qevent.h>
#if QT_CONFIG(shortcut)
# include <QtGui/private/qshortcutmap_p.h>
@@ -13,10 +15,10 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtQuick/private/qquickitem_p.h>
-#include <QtCore/qpointer.h>
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcAction, "qt.quick.controls.action")
+
/*!
\qmltype Action
\inherits QtObject
@@ -316,6 +318,7 @@ QQuickAction::QQuickAction(QObject *parent)
QQuickAction::~QQuickAction()
{
Q_D(QQuickAction);
+ qCDebug(lcAction) << "destroying" << this << d->text;
if (d->group)
d->group->removeAction(this);
diff --git a/src/quicktemplates/qquickdialog.cpp b/src/quicktemplates/qquickdialog.cpp
index 30daee5f33..7a1c5d513b 100644
--- a/src/quicktemplates/qquickdialog.cpp
+++ b/src/quicktemplates/qquickdialog.cpp
@@ -6,6 +6,7 @@
#include "qquickdialogbuttonbox_p.h"
#include "qquickabstractbutton_p.h"
#include "qquickpopupitem_p_p.h"
+#include "qquickpopupwindow_p_p.h"
QT_BEGIN_NAMESPACE
@@ -164,6 +165,11 @@ void QQuickDialogPrivate::handleClick(QQuickAbstractButton *button)
}
}
+Qt::WindowFlags QQuickDialogPrivate::popupWindowType() const
+{
+ return Qt::Dialog;
+}
+
QQuickDialog::QQuickDialog(QObject *parent)
: QQuickDialog(*(new QQuickDialogPrivate), parent)
{
@@ -176,8 +182,6 @@ QQuickDialog::QQuickDialog(QQuickDialogPrivate &dd, QObject *parent)
// Dialogs should get active focus when opened so that e.g. Cancel closes them.
setFocus(true);
-
- QObject::connect(d->popupItem, &QQuickPopupItem::titleChanged, this, &QQuickDialog::titleChanged);
QObject::connect(d->popupItem, &QQuickPopupItem::headerChanged, this, &QQuickDialog::headerChanged);
QObject::connect(d->popupItem, &QQuickPopupItem::footerChanged, this, &QQuickDialog::footerChanged);
QObject::connect(d->popupItem, &QQuickPopupItem::implicitHeaderWidthChanged, this, &QQuickDialog::implicitHeaderWidthChanged);
@@ -189,7 +193,6 @@ QQuickDialog::QQuickDialog(QQuickDialogPrivate &dd, QObject *parent)
QQuickDialog::~QQuickDialog()
{
Q_D(QQuickDialog);
- QObject::disconnect(d->popupItem, &QQuickPopupItem::titleChanged, this, &QQuickDialog::titleChanged);
QObject::disconnect(d->popupItem, &QQuickPopupItem::headerChanged, this, &QQuickDialog::headerChanged);
QObject::disconnect(d->popupItem, &QQuickPopupItem::footerChanged, this, &QQuickDialog::footerChanged);
QObject::disconnect(d->popupItem, &QQuickPopupItem::implicitHeaderWidthChanged, this, &QQuickDialog::implicitHeaderWidthChanged);
@@ -218,13 +221,22 @@ QQuickDialog::~QQuickDialog()
QString QQuickDialog::title() const
{
Q_D(const QQuickDialog);
- return d->popupItem->title();
+ return d->m_title;
}
void QQuickDialog::setTitle(const QString &title)
{
Q_D(QQuickDialog);
- d->popupItem->setTitle(title);
+ if (d->m_title == title)
+ return;
+ d->m_title = title;
+
+ if (d->popupWindow)
+ d->popupWindow->setTitle(title);
+ else
+ d->popupItem->setTitle(title);
+
+ emit titleChanged();
}
/*!
@@ -488,6 +500,12 @@ qreal QQuickDialog::implicitFooterHeight() const
return d->popupItem->implicitFooterHeight();
}
+void QQuickDialog::setOpacity(qreal opacity)
+{
+ Q_D(QQuickDialog);
+ QQuickPopup::setOpacity(d->popupWindow ? qreal(!qFuzzyIsNull(opacity)) : opacity);
+}
+
/*!
\qmlmethod void QtQuick.Controls::Dialog::accept()
diff --git a/src/quicktemplates/qquickdialog_p.h b/src/quicktemplates/qquickdialog_p.h
index 63fac39f97..c28e687b79 100644
--- a/src/quicktemplates/qquickdialog_p.h
+++ b/src/quicktemplates/qquickdialog_p.h
@@ -74,6 +74,8 @@ public:
qreal implicitFooterWidth() const;
qreal implicitFooterHeight() const;
+ void setOpacity(qreal opacity) override;
+
public Q_SLOTS:
virtual void accept();
virtual void reject();
diff --git a/src/quicktemplates/qquickdialog_p_p.h b/src/quicktemplates/qquickdialog_p_p.h
index dd4c3fa1f0..9b0e5d177a 100644
--- a/src/quicktemplates/qquickdialog_p_p.h
+++ b/src/quicktemplates/qquickdialog_p_p.h
@@ -40,6 +40,8 @@ public:
virtual void handleReject();
virtual void handleClick(QQuickAbstractButton *button);
+ Qt::WindowFlags popupWindowType() const override;
+
int result = 0;
QString title;
QQuickDialogButtonBox *buttonBox = nullptr;
diff --git a/src/quicktemplates/qquickdrawer.cpp b/src/quicktemplates/qquickdrawer.cpp
index f67a8ec76a..e240f8c612 100644
--- a/src/quicktemplates/qquickdrawer.cpp
+++ b/src/quicktemplates/qquickdrawer.cpp
@@ -596,6 +596,11 @@ bool QQuickDrawerPrivate::prepareExitTransition()
return QQuickPopupPrivate::prepareExitTransition();
}
+Qt::WindowFlags QQuickDrawerPrivate::popupWindowType() const
+{
+ return Qt::Widget;
+}
+
bool QQuickDrawerPrivate::setEdge(Qt::Edge e)
{
Q_Q(QQuickDrawer);
diff --git a/src/quicktemplates/qquickdrawer_p_p.h b/src/quicktemplates/qquickdrawer_p_p.h
index 7eae26b0cb..f7757fa1a9 100644
--- a/src/quicktemplates/qquickdrawer_p_p.h
+++ b/src/quicktemplates/qquickdrawer_p_p.h
@@ -54,6 +54,8 @@ public:
bool prepareEnterTransition() override;
bool prepareExitTransition() override;
+ Qt::WindowFlags popupWindowType() const override;
+
bool setEdge(Qt::Edge edge);
Qt::Edge effectiveEdge() const;
bool isWithinDragMargin(const QPointF &point) const;
diff --git a/src/quicktemplates/qquickheaderview.cpp b/src/quicktemplates/qquickheaderview.cpp
index b94280865f..dedf3a23e1 100644
--- a/src/quicktemplates/qquickheaderview.cpp
+++ b/src/quicktemplates/qquickheaderview.cpp
@@ -64,6 +64,20 @@
\include qquickheaderview.qdocinc {textRole}
*/
+/*!
+ \qmlproperty bool QtQuick.Controls::HorizontalHeaderView::movableColumns
+ \since 6.8
+
+ \include qquickheaderview.qdocinc {movableColumns}
+*/
+
+/*!
+ \qmlproperty bool QtQuick.Controls::VerticalHeaderView::movableRows
+ \since 6.8
+
+ \include qquickheaderview.qdocinc {movableRows}
+*/
+
QT_BEGIN_NAMESPACE
QQuickHeaderViewBasePrivate::QQuickHeaderViewBasePrivate()
@@ -173,6 +187,26 @@ QAbstractItemModel *QQuickHeaderViewBasePrivate::selectionSourceModel()
return &m_headerDataProxyModel;
}
+int QQuickHeaderViewBasePrivate::logicalRowIndex(const int visualIndex) const
+{
+ return (m_headerDataProxyModel.orientation() == Qt::Horizontal) ? visualIndex : QQuickTableViewPrivate::logicalRowIndex(visualIndex);
+}
+
+int QQuickHeaderViewBasePrivate::logicalColumnIndex(const int visualIndex) const
+{
+ return (m_headerDataProxyModel.orientation() == Qt::Vertical) ? visualIndex : QQuickTableViewPrivate::logicalColumnIndex(visualIndex);
+}
+
+int QQuickHeaderViewBasePrivate::visualRowIndex(const int logicalIndex) const
+{
+ return (m_headerDataProxyModel.orientation() == Qt::Horizontal) ? logicalIndex : QQuickTableViewPrivate::visualRowIndex(logicalIndex);
+}
+
+int QQuickHeaderViewBasePrivate::visualColumnIndex(const int logicalIndex) const
+{
+ return (m_headerDataProxyModel.orientation() == Qt::Vertical) ? logicalIndex : QQuickTableViewPrivate::visualColumnIndex(logicalIndex);
+}
+
QQuickHeaderViewBase::QQuickHeaderViewBase(Qt::Orientation orient, QQuickItem *parent)
: QQuickTableView(*(new QQuickHeaderViewBasePrivate), parent)
{
@@ -415,6 +449,30 @@ QQuickHorizontalHeaderView::QQuickHorizontalHeaderView(QQuickItem *parent)
QQuickHorizontalHeaderView::~QQuickHorizontalHeaderView()
{
+ Q_D(QQuickHorizontalHeaderView);
+ d->destroySectionDragHandler();
+}
+
+bool QQuickHorizontalHeaderView::movableColumns() const
+{
+ Q_D(const QQuickHorizontalHeaderView);
+ return d->m_movableColumns;
+}
+
+void QQuickHorizontalHeaderView::setMovableColumns(bool movableColumns)
+{
+ Q_D(QQuickHorizontalHeaderView);
+ if (d->m_movableColumns == movableColumns)
+ return;
+
+ d->m_movableColumns = movableColumns;
+
+ if (d->m_movableColumns)
+ d->initSectionDragHandler(Qt::Horizontal);
+ else
+ d->destroySectionDragHandler();
+
+ emit movableColumnsChanged();
}
QQuickVerticalHeaderView::QQuickVerticalHeaderView(QQuickItem *parent)
@@ -426,6 +484,30 @@ QQuickVerticalHeaderView::QQuickVerticalHeaderView(QQuickItem *parent)
QQuickVerticalHeaderView::~QQuickVerticalHeaderView()
{
+ Q_D(QQuickVerticalHeaderView);
+ d->destroySectionDragHandler();
+}
+
+bool QQuickVerticalHeaderView::movableRows() const
+{
+ Q_D(const QQuickVerticalHeaderView);
+ return d->m_movableRows ;
+}
+
+void QQuickVerticalHeaderView::setMovableRows(bool movableRows)
+{
+ Q_D(QQuickVerticalHeaderView);
+ if (d->m_movableRows == movableRows)
+ return;
+
+ d->m_movableRows = movableRows;
+
+ if (d->m_movableRows)
+ d->initSectionDragHandler(Qt::Vertical);
+ else
+ d->destroySectionDragHandler();
+
+ emit movableRowsChanged();
}
QQuickHorizontalHeaderViewPrivate::QQuickHorizontalHeaderViewPrivate() = default;
diff --git a/src/quicktemplates/qquickheaderview_p.h b/src/quicktemplates/qquickheaderview_p.h
index 5280f563dc..ba123a3c3e 100644
--- a/src/quicktemplates/qquickheaderview_p.h
+++ b/src/quicktemplates/qquickheaderview_p.h
@@ -52,6 +52,7 @@ class Q_QUICKTEMPLATES2_EXPORT QQuickHorizontalHeaderView : public QQuickHeaderV
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickHorizontalHeaderView)
+ Q_PROPERTY(bool movableColumns READ movableColumns WRITE setMovableColumns NOTIFY movableColumnsChanged REVISION(6, 8) FINAL)
QML_NAMED_ELEMENT(HorizontalHeaderView)
QML_ADDED_IN_VERSION(2, 15)
@@ -59,6 +60,12 @@ public:
QQuickHorizontalHeaderView(QQuickItem *parent = nullptr);
~QQuickHorizontalHeaderView() override;
+ bool movableColumns() const;
+ void setMovableColumns(bool movableColumns);
+
+Q_SIGNALS:
+ Q_REVISION(6, 8) void movableColumnsChanged();
+
protected:
QQuickHorizontalHeaderView(QQuickHorizontalHeaderViewPrivate &dd, QQuickItem *parent);
@@ -71,6 +78,7 @@ class Q_QUICKTEMPLATES2_EXPORT QQuickVerticalHeaderView : public QQuickHeaderVie
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickVerticalHeaderView)
+ Q_PROPERTY(bool movableRows READ movableRows WRITE setMovableRows NOTIFY movableRowsChanged REVISION(6, 8) FINAL)
QML_NAMED_ELEMENT(VerticalHeaderView)
QML_ADDED_IN_VERSION(2, 15)
@@ -78,6 +86,12 @@ public:
QQuickVerticalHeaderView(QQuickItem *parent = nullptr);
~QQuickVerticalHeaderView() override;
+ bool movableRows() const;
+ void setMovableRows(bool movableRows);
+
+Q_SIGNALS:
+ Q_REVISION(6, 8) void movableRowsChanged();
+
protected:
QQuickVerticalHeaderView(QQuickVerticalHeaderViewPrivate &dd, QQuickItem *parent);
diff --git a/src/quicktemplates/qquickheaderview_p_p.h b/src/quicktemplates/qquickheaderview_p_p.h
index 4269d1c1a0..63abd58aa3 100644
--- a/src/quicktemplates/qquickheaderview_p_p.h
+++ b/src/quicktemplates/qquickheaderview_p_p.h
@@ -88,6 +88,11 @@ protected:
QStack<SectionSize> m_hiddenSectionSizes;
bool m_modelExplicitlySetByUser = false;
QString m_textRole;
+
+ int logicalRowIndex(const int visualIndex) const final;
+ int logicalColumnIndex(const int visualIndex) const final;
+ int visualRowIndex(const int logicalIndex) const final;
+ int visualColumnIndex(const int logicalIndex) const final;
};
class QQuickHorizontalHeaderViewPrivate : public QQuickHeaderViewBasePrivate
@@ -96,6 +101,8 @@ class QQuickHorizontalHeaderViewPrivate : public QQuickHeaderViewBasePrivate
public:
QQuickHorizontalHeaderViewPrivate();
~QQuickHorizontalHeaderViewPrivate();
+
+ bool m_movableColumns = false;
};
class QQuickVerticalHeaderViewPrivate : public QQuickHeaderViewBasePrivate
@@ -104,6 +111,8 @@ class QQuickVerticalHeaderViewPrivate : public QQuickHeaderViewBasePrivate
public:
QQuickVerticalHeaderViewPrivate();
~QQuickVerticalHeaderViewPrivate();
+
+ bool m_movableRows = false;
};
QT_END_NAMESPACE
diff --git a/src/quicktemplates/qquickmenu.cpp b/src/quicktemplates/qquickmenu.cpp
index 707b115983..3ab99ecd87 100644
--- a/src/quicktemplates/qquickmenu.cpp
+++ b/src/quicktemplates/qquickmenu.cpp
@@ -7,18 +7,23 @@
#include <private/qtquicktemplates2-config_p.h>
#if QT_CONFIG(quicktemplates2_container)
#include "qquickmenubaritem_p.h"
-#include "qquickmenubar_p.h"
+#include "qquickmenubar_p_p.h"
#endif
+#include "qquickmenuseparator_p.h"
+#include "qquicknativemenuitem_p.h"
#include "qquickpopupitem_p_p.h"
#include "qquickpopuppositioner_p_p.h"
#include "qquickaction_p.h"
+#include <QtCore/qloggingcategory.h>
#include <QtGui/qevent.h>
#include <QtGui/qcursor.h>
#if QT_CONFIG(shortcut)
#include <QtGui/qkeysequence.h>
#endif
#include <QtGui/qpa/qplatformintegration.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlcomponent.h>
@@ -30,10 +35,15 @@
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickitemchangelistener_p.h>
#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuick/private/qquicklistview_p.h>
+#include <QtQuick/private/qquickrendercontrol_p.h>
#include <QtQuick/private/qquickwindow_p.h>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcMenu, "qt.quick.controls.menu")
+Q_LOGGING_CATEGORY(lcNativeMenus, "qt.quick.controls.nativemenus")
+
// copied from qfusionstyle.cpp
static const int SUBMENU_DELAY = 225;
@@ -47,7 +57,13 @@ static const int SUBMENU_DELAY = 225;
\ingroup qtquickcontrols-popups
\brief Menu popup that can be used as a context menu or popup menu.
- \image qtquickcontrols-menu.png
+ \table
+ \row
+ \li \image qtquickcontrols-menu-native.png
+ \caption Native macOS menu.
+ \li \image qtquickcontrols-menu.png
+ \caption Non-native \l {Material Style}{Material style} menu.
+ \endtable
Menu has two main use cases:
\list
@@ -184,6 +200,45 @@ static const int SUBMENU_DELAY = 225;
\sa {Customizing Menu}, MenuItem, {Menu Controls}, {Popup Controls},
{Dynamic QML Object Creation from JavaScript}
+
+ \section1 Native Menus
+
+ Since Qt 6.8, Menu is backed by a native menu by default, on platforms
+ where it is supported:
+ \list
+ \li Android
+ \li iOS
+ \li Linux (only available as a stand-alone context menu when running with the GTK+ platform theme)
+ \li macOS
+ \li Windows
+ \endlist
+
+ To use non-native menus by default, set \l {Qt::ApplicationAttribute}
+ {Qt::AA_DontUseNativeMenuWindows} to \c true.
+
+ As not all platforms support the full set of Menu's API, only a common
+ subset of it is supported when using a native menu:
+ \list
+ \li \l {Popup::}{x}
+ \li \l {Popup::}{y}
+ \li \l {Popup::}{visible}
+ \li \l {Popup::}{opened}
+ \li \l title
+ \li \l count
+ \li \l {Popup::}{contentData}
+ \li \l {Popup::}{contentChildren} (visual children will not be visible)
+ \li \l contentModel
+ \li \l {Popup::}{open()}
+ \li \l {Popup::}{close()}
+ \li \l {Popup::}{opened()}
+ \li \l {Popup::}{closed()}
+ \li \l {Popup::}{aboutToShow()}
+ \li \l {Popup::}{aboutToHide()}
+ \endlist
+
+ Items like \l MenuItem will still react to clicks in the corresponding
+ native menu item by emitting signals, for example, but will be replaced by
+ their native counterpart.
*/
/*!
@@ -197,6 +252,8 @@ static const int SUBMENU_DELAY = 225;
The default value is \c true.
+ \include qquickmenu.qdocinc non-native-only-property
+
\sa {Popup::}{activeFocus}
*/
@@ -230,6 +287,267 @@ void QQuickMenuPrivate::init()
contentModel = new QQmlObjectModel(q);
}
+QQuickMenu *QQuickMenuPrivate::rootMenu() const
+{
+ Q_Q(const QQuickMenu);
+ const QQuickMenu *rootMenu = q;
+ const QObject *p = q->parent();
+ while (p) {
+ if (auto menu = qobject_cast<const QQuickMenu *>(p))
+ rootMenu = menu;
+ p = p->parent();
+ }
+
+ return const_cast<QQuickMenu *>(rootMenu);
+}
+
+bool QQuickMenuPrivate::useNativeMenu() const
+{
+ // If we're inside a MenuBar, it'll decide whether or not we
+ // should be native or not. Otherwise, the root menu (which
+ // might be this menu) will decide.
+ QQuickMenu *root = rootMenu();
+ if (auto menuBar = QQuickMenuPrivate::get(root)->menuBar.get())
+ return QQuickMenuBarPrivate::get(menuBar)->useNativeMenu(q_func());
+ return m_popupType == QQuickPopup::Native;
+}
+
+QPlatformMenu *QQuickMenuPrivate::nativeHandle()
+{
+ Q_ASSERT(handle || useNativeMenu());
+ if (!handle && !triedToCreateNativeMenu)
+ createNativeMenu();
+ return handle.get();
+}
+
+QPlatformMenu *QQuickMenuPrivate::maybeNativeHandle() const
+{
+ return handle.get();
+}
+
+bool QQuickMenuPrivate::createNativeMenu()
+{
+ Q_ASSERT(!handle);
+ Q_Q(QQuickMenu);
+ qCDebug(lcNativeMenus) << "createNativeMenu called on" << q;
+
+ if (auto menuBar = QQuickMenuPrivate::get(rootMenu())->menuBar) {
+ auto menuBarPrivate = QQuickMenuBarPrivate::get(menuBar);
+ if (menuBarPrivate->useNativeMenuBar()) {
+ qCDebug(lcNativeMenus) << "- creating native menu from native menubar";
+ if (QPlatformMenuBar *menuBarHandle = menuBarPrivate->nativeHandle())
+ handle.reset(menuBarHandle->createMenu());
+ }
+ }
+
+ if (!handle) {
+ QPlatformMenu *parentMenuHandle(parentMenu ? get(parentMenu)->handle.get() : nullptr);
+ if (parentMenu && parentMenuHandle) {
+ qCDebug(lcNativeMenus) << "- creating native sub-menu";
+ handle.reset(parentMenuHandle->createSubMenu());
+ } else {
+ qCDebug(lcNativeMenus) << "- creating native menu";
+ handle.reset(QGuiApplicationPrivate::platformTheme()->createPlatformMenu());
+ }
+ }
+
+ triedToCreateNativeMenu = true;
+
+ if (!handle)
+ return false;
+
+ q->connect(handle.get(), &QPlatformMenu::aboutToShow, q, [q, this](){
+ emit q->aboutToShow();
+ visible = true;
+ emit q->visibleChanged();
+ emit q->openedChanged();
+ opened();
+ });
+ q->connect(handle.get(), &QPlatformMenu::aboutToHide, q, [q, this](){
+ qCDebug(lcNativeMenus) << "QPlatformMenu::aboutToHide called; about to call setVisible(false) on Menu";
+ emit q->aboutToHide();
+ visible = false;
+ emit q->visibleChanged();
+ emit q->openedChanged();
+ emit q->closed();
+ });
+
+ recursivelyCreateNativeMenuItems(q);
+ syncWithNativeMenu();
+
+ return true;
+}
+
+QString nativeMenuItemListToString(const QList<QQuickNativeMenuItem *> &nativeItems)
+{
+ if (nativeItems.isEmpty())
+ return QStringLiteral("(Empty)");
+
+ QString str;
+ QTextStream debug(&str);
+ for (const auto *nativeItem : nativeItems)
+ debug << nativeItem->debugText() << ", ";
+ // Remove trailing space and comma.
+ if (!nativeItems.isEmpty())
+ str.chop(2);
+ return str;
+}
+
+void QQuickMenuPrivate::syncWithNativeMenu()
+{
+ Q_Q(QQuickMenu);
+ if (!complete || !handle)
+ return;
+
+ qCDebug(lcNativeMenus).nospace() << "syncWithNativeMenu called on " << q
+ << " (complete: " << complete << " visible: " << visible << ") - "
+ << "syncing " << nativeItems.size() << " item(s)...";
+
+ // TODO: call this function when any of the variables below change
+
+ handle->setText(title);
+ handle->setEnabled(q->isEnabled());
+ handle->setMinimumWidth(q->implicitWidth());
+// nativeHandle->setMenuType(m_type);
+ handle->setFont(q->font());
+
+ // Note: the QQuickMenu::visible property is used to open or close the menu.
+ // This is in contrast to QPlatformMenu::visible, which tells if the menu
+ // should be visible in the menubar or not (if it belongs to one). To control
+ // if a QPlatformMenu should be open, we instead use QPlatformMenu::showPopup()
+ // and dismiss(). As such, we don't want to call handle->setVisible(visible)
+ // from this function since we always want the menu to be visible in the menubar
+ // (if it belongs to one). The currently only way to hide a menu from a menubar is
+ // to instead call MenuBar.removeMenu(menu).
+
+// if (m_menuBar && m_menuBar->handle())
+// m_menuBar->handle()->syncMenu(handle);
+//#if QT_CONFIG(systemtrayicon)
+// else if (m_systemTrayIcon && m_systemTrayIcon->handle())
+// m_systemTrayIcon->handle()->updateMenu(handle);
+//#endif
+
+ for (QQuickNativeMenuItem *item : std::as_const(nativeItems)) {
+ qCDebug(lcNativeMenus) << "- syncing" << item << "action" << item->action()
+ << "sub-menu" << item->subMenu() << item->debugText();
+ item->sync();
+ }
+
+ qCDebug(lcNativeMenus) << "... finished syncing" << q;
+}
+
+void QQuickMenuPrivate::removeNativeMenu()
+{
+ // Remove the native menu, including it's native menu items
+ Q_Q(QQuickMenu);
+ const int qtyItemsToRemove = nativeItems.size();
+ if (qtyItemsToRemove != 0)
+ Q_ASSERT(q->count() == qtyItemsToRemove);
+ for (int i = 0; i < qtyItemsToRemove; ++i)
+ removeNativeItem(0);
+ Q_ASSERT(nativeItems.isEmpty());
+
+ // removeNativeItem will take care of destroying sub-menus and resetting their native data,
+ // but as the root menu, we have to take care of our own.
+ resetNativeData();
+}
+
+void QQuickMenuPrivate::syncWithUseNativeMenu()
+{
+ Q_Q(QQuickMenu);
+ // Users can change AA_DontUseNativeMenuWindows while a menu is visible,
+ // but the changes won't take affect until the menu is re-opened.
+ if (q->isVisible() || parentMenu)
+ return;
+
+ if (maybeNativeHandle() && !useNativeMenu()) {
+ // Switch to a non-native menu by removing the native menu and its native items.
+ // Note that there's nothing to do if a native menu was requested but we failed to create it.
+ removeNativeMenu();
+ } else if (useNativeMenu()) {
+ Q_ASSERT(nativeItems.isEmpty());
+ // Try to create a native menu.
+ nativeHandle();
+ }
+}
+
+/*!
+ \internal
+
+ Recursively destroys native sub-menus of \a menu.
+
+ This function checks if each native item in \c menu has a sub-menu,
+ and if so:
+ \list
+ \li Calls itself with that sub-menu
+ \li Resets the item's data (important to avoid accessing a deleted QQuickAction
+ when printing in QQuickNativeMenuItem's destructor)
+ \li Deletes (eventually) the native item
+ \endlist
+
+ Similar (besides the recursion) to removeNativeItem(), except that
+ we can avoid repeated calls to syncWithNativeMenu().
+*/
+void QQuickMenuPrivate::recursivelyDestroyNativeSubMenus(QQuickMenu *menu)
+{
+ auto *menuPrivate = QQuickMenuPrivate::get(menu);
+ Q_ASSERT(menuPrivate->handle);
+ qCDebug(lcNativeMenus) << "recursivelyDestroyNativeSubMenus called with" << menu << "...";
+
+ while (!menuPrivate->nativeItems.isEmpty()) {
+ std::unique_ptr<QQuickNativeMenuItem> item(menuPrivate->nativeItems.takeFirst());
+ qCDebug(lcNativeMenus) << "- taking and destroying" << item->debugText();
+ if (QQuickMenu *subMenu = item->subMenu())
+ recursivelyDestroyNativeSubMenus(subMenu);
+
+ if (item->handle())
+ menuPrivate->handle->removeMenuItem(item->handle());
+ }
+
+ menuPrivate->resetNativeData();
+
+ qCDebug(lcNativeMenus) << "... finished destroying native sub-menus of" << menu;
+}
+
+static QWindow *effectiveWindow(QWindow *window, QPoint *offset)
+{
+ QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(window);
+ if (quickWindow) {
+ QWindow *renderWindow = QQuickRenderControl::renderWindowFor(quickWindow, offset);
+ if (renderWindow)
+ return renderWindow;
+ }
+ return window;
+}
+
+void QQuickMenuPrivate::setNativeMenuVisible(bool visible)
+{
+ Q_Q(QQuickMenu);
+ qCDebug(lcNativeMenus) << "setNativeMenuVisible called with visible" << visible;
+ if (visible)
+ emit q->aboutToShow();
+ else
+ emit q->aboutToHide();
+
+ this->visible = visible;
+ syncWithNativeMenu();
+
+ QPoint offset;
+ QWindow *window = effectiveWindow(qGuiApp->topLevelWindows().first(), &offset);
+
+ if (visible) {
+ lastDevicePixelRatio = window->devicePixelRatio();
+
+ const QPointF globalPos = parentItem->mapToGlobal(x, y);
+ const QPoint windowPos = window->mapFromGlobal(globalPos.toPoint());
+ QRect targetRect(windowPos, QSize(0, 0));
+ handle->showPopup(window, QHighDpi::toNativePixels(targetRect, window),
+ /*menuItem ? menuItem->handle() : */nullptr);
+ } else {
+ handle->dismiss();
+ }
+}
+
QQuickItem *QQuickMenuPrivate::itemAt(int index) const
{
return qobject_cast<QQuickItem *>(contentModel->get(index));
@@ -237,6 +555,9 @@ QQuickItem *QQuickMenuPrivate::itemAt(int index) const
void QQuickMenuPrivate::insertItem(int index, QQuickItem *item)
{
+ qCDebug(lcMenu) << "insert called with index" << index << "item" << item;
+
+ Q_Q(QQuickMenu);
contentData.append(item);
item->setParentItem(contentItem);
QQuickItemPrivate::get(item)->setCulled(true); // QTBUG-53262
@@ -248,23 +569,90 @@ void QQuickMenuPrivate::insertItem(int index, QQuickItem *item)
QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item);
if (menuItem) {
- Q_Q(QQuickMenu);
QQuickMenuItemPrivate::get(menuItem)->setMenu(q);
if (QQuickMenu *subMenu = menuItem->subMenu())
QQuickMenuPrivate::get(subMenu)->setParentMenu(q);
QObjectPrivate::connect(menuItem, &QQuickMenuItem::triggered, this, &QQuickMenuPrivate::onItemTriggered);
+ QObjectPrivate::connect(menuItem, &QQuickMenuItem::implicitTextPaddingChanged, this, &QQuickMenuPrivate::updateTextPadding);
+ QObjectPrivate::connect(menuItem, &QQuickMenuItem::visibleChanged, this, &QQuickMenuPrivate::updateTextPadding);
QObjectPrivate::connect(menuItem, &QQuickItem::activeFocusChanged, this, &QQuickMenuPrivate::onItemActiveFocusChanged);
QObjectPrivate::connect(menuItem, &QQuickControl::hoveredChanged, this, &QQuickMenuPrivate::onItemHovered);
}
+
+ if (maybeNativeHandle() && complete)
+ maybeCreateAndInsertNativeItem(index, item);
+
+ if (lcMenu().isDebugEnabled())
+ printContentModelItems();
+
+ updateTextPadding();
+}
+
+void QQuickMenuPrivate::maybeCreateAndInsertNativeItem(int index, QQuickItem *item)
+{
+ Q_Q(QQuickMenu);
+ Q_ASSERT(complete);
+ Q_ASSERT_X(handle, Q_FUNC_INFO, qPrintable(QString::fromLatin1(
+ "Expected %1 to be using a native menu").arg(QDebug::toString(q))));
+ std::unique_ptr<QQuickNativeMenuItem> nativeMenuItem(QQuickNativeMenuItem::createFromNonNativeItem(q, item));
+ if (!nativeMenuItem) {
+ // TODO: fall back to non-native menu
+ qmlWarning(q) << "Native menu failed to create a native menu item for item at index" << index;
+ return;
+ }
+
+ nativeItems.insert(index, nativeMenuItem.get());
+
+ // Having a QQuickNativeMenuItem doesn't mean that we were able to create a native handle:
+ // it could be e.g. a Rectangle. See comment in QQuickNativeMenuItem::createFromNonNativeItem.
+ if (nativeMenuItem->handle()) {
+ QQuickNativeMenuItem *before = nativeItems.value(index + 1);
+ handle->insertMenuItem(nativeMenuItem->handle(), before ? before->handle() : nullptr);
+ qCDebug(lcNativeMenus) << "inserted native menu item at index" << index
+ << "before" << (before ? before->debugText() : QStringLiteral("null"));
+
+ if (nativeMenuItem->subMenu() && QQuickMenuPrivate::get(nativeMenuItem->subMenu())->nativeItems.count()
+ < nativeMenuItem->subMenu()->count()) {
+ // We're inserting a sub-menu item, and it hasn't had native items added yet,
+ // which probably means it's a menu that's been added back in after being removed
+ // with takeMenu(). Sub-menus added for the first time have their native items already
+ // constructed by virtue of contentData_append. Sub-menus that are removed always
+ // have their native items destroyed and removed too.
+ recursivelyCreateNativeMenuItems(nativeMenuItem->subMenu());
+ }
+ }
+
+ nativeMenuItem.release();
+
+ qCDebug(lcNativeMenus) << "nativeItems now contains the following items:"
+ << nativeMenuItemListToString(nativeItems);
}
void QQuickMenuPrivate::moveItem(int from, int to)
{
contentModel->move(from, to);
+
+ if (maybeNativeHandle())
+ nativeItems.move(from, to);
}
-void QQuickMenuPrivate::removeItem(int index, QQuickItem *item)
+/*!
+ \internal
+
+ Removes the specified \a item, potentially destroying it depending on
+ \a destructionPolicy.
+
+ \note the native menu item is destroyed regardless of the destruction
+ policy, because it's an implementation detail and hence is not created by
+ or available to the user.
+*/
+void QQuickMenuPrivate::removeItem(int index, QQuickItem *item, DestructionPolicy destructionPolicy)
{
+ qCDebug(lcMenu) << "removeItem called with index" << index << "item" << item;
+
+ if (maybeNativeHandle())
+ removeNativeItem(index);
+
contentData.removeOne(item);
QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent);
@@ -278,9 +666,79 @@ void QQuickMenuPrivate::removeItem(int index, QQuickItem *item)
if (QQuickMenu *subMenu = menuItem->subMenu())
QQuickMenuPrivate::get(subMenu)->setParentMenu(nullptr);
QObjectPrivate::disconnect(menuItem, &QQuickMenuItem::triggered, this, &QQuickMenuPrivate::onItemTriggered);
+ QObjectPrivate::disconnect(menuItem, &QQuickMenuItem::implicitTextPaddingChanged, this, &QQuickMenuPrivate::updateTextPadding);
+ QObjectPrivate::disconnect(menuItem, &QQuickMenuItem::visibleChanged, this, &QQuickMenuPrivate::updateTextPadding);
QObjectPrivate::disconnect(menuItem, &QQuickItem::activeFocusChanged, this, &QQuickMenuPrivate::onItemActiveFocusChanged);
QObjectPrivate::disconnect(menuItem, &QQuickControl::hoveredChanged, this, &QQuickMenuPrivate::onItemHovered);
}
+
+ if (destructionPolicy == DestructionPolicy::Destroy)
+ item->deleteLater();
+
+ if (lcMenu().isDebugEnabled())
+ printContentModelItems();
+}
+
+void QQuickMenuPrivate::removeNativeItem(int index)
+{
+ // Either we're still using native menus and are removing item(s), or we've switched
+ // to a non-native menu; either way, we should actually have items to remove before we're called.
+ Q_ASSERT(handle);
+ Q_ASSERT_X(index >= 0 && index < nativeItems.size(), Q_FUNC_INFO, qPrintable(QString::fromLatin1(
+ "index %1 is less than 0 or greater than or equal to %2").arg(index).arg(nativeItems.size())));
+
+ // We can delete the item synchronously because there aren't any external (e.g. QML)
+ // references to it.
+ std::unique_ptr<QQuickNativeMenuItem> nativeItem(nativeItems.takeAt(index));
+ qCDebug(lcNativeMenus) << "removing native item" << nativeItem->debugText() << "at index" << index
+ << "from" << q_func() << "...";
+ if (QQuickMenu *subMenu = nativeItem->subMenu())
+ recursivelyDestroyNativeSubMenus(subMenu);
+
+ if (nativeItem->handle()) {
+ handle->removeMenuItem(nativeItem->handle());
+ syncWithNativeMenu();
+ }
+
+ qCDebug(lcNativeMenus).nospace() << "... after removing item at index " << index
+ << ", nativeItems now contains the following items: " << nativeMenuItemListToString(nativeItems);
+}
+
+void QQuickMenuPrivate::resetNativeData()
+{
+ qCDebug(lcNativeMenus) << "resetNativeData called on" << q_func();
+ handle.reset();
+ triedToCreateNativeMenu = false;
+}
+
+void QQuickMenuPrivate::recursivelyCreateNativeMenuItems(QQuickMenu *menu)
+{
+ auto *menuPrivate = QQuickMenuPrivate::get(menu);
+ // If we're adding a sub-menu, we need to ensure its handle has been created
+ // before trying to create native items for it.
+ if (!menuPrivate->triedToCreateNativeMenu)
+ menuPrivate->createNativeMenu();
+
+ const int qtyItemsToCreate = menuPrivate->contentModel->count();
+ if (menuPrivate->nativeItems.count() == qtyItemsToCreate)
+ return;
+
+ qCDebug(lcNativeMenus) << "recursively creating" << qtyItemsToCreate << "menu item(s) for" << menu;
+ Q_ASSERT(menuPrivate->nativeItems.count() == 0);
+ for (int i = 0; i < qtyItemsToCreate; ++i) {
+ QQuickItem *item = menu->itemAt(i);
+ menuPrivate->maybeCreateAndInsertNativeItem(i, item);
+ auto *menuItem = qobject_cast<QQuickMenuItem *>(item);
+ if (menuItem && menuItem->subMenu())
+ recursivelyCreateNativeMenuItems(menuItem->subMenu());
+ }
+}
+
+void QQuickMenuPrivate::printContentModelItems() const
+{
+ qCDebug(lcMenu) << "contentModel now contains:";
+ for (int i = 0; i < contentModel->count(); ++i)
+ qCDebug(lcMenu) << "-" << itemAt(i);
}
QQuickItem *QQuickMenuPrivate::beginCreateItem()
@@ -415,18 +873,29 @@ QQuickPopupPositioner *QQuickMenuPrivate::getPositioner()
void QQuickMenuPositioner::reposition()
{
QQuickMenu *menu = static_cast<QQuickMenu *>(popup());
- QQuickMenuPrivate *p = QQuickMenuPrivate::get(menu);
- if (p->parentMenu) {
- if (p->cascade) {
- if (p->popupItem->isMirrored())
- menu->setPosition(QPointF(-menu->width() - p->parentMenu->leftPadding() + menu->overlap(), -menu->topPadding()));
- else if (p->parentItem)
- menu->setPosition(QPointF(p->parentItem->width() + p->parentMenu->rightPadding() - menu->overlap(), -menu->topPadding()));
+ QQuickMenuPrivate *menu_d = QQuickMenuPrivate::get(menu);
+
+ if (QQuickMenu *parentMenu = menu_d->parentMenu) {
+ if (menu_d->cascade) {
+ // Align the menu to the frame of the parent menu, minus overlap. The position
+ // should be in the coordinate system of the parentItem.
+ if (menu_d->popupItem->isMirrored()) {
+ menu->setPosition({-menu->width()
+ - parentMenu->leftPadding() + parentMenu->leftInset()
+ + menu->overlap(),
+ menu->topInset() - menu->topPadding()});
+ } else if (menu_d->parentItem) {
+ menu->setPosition({menu_d->parentItem->width()
+ + parentMenu->rightPadding() - parentMenu->rightInset()
+ - menu->overlap(),
+ menu->topInset() - menu->topPadding()});
+ }
} else {
- menu->setPosition(QPointF(p->parentMenu->x() + (p->parentMenu->width() - menu->width()) / 2,
- p->parentMenu->y() + (p->parentMenu->height() - menu->height()) / 2));
+ menu->setPosition(QPointF(parentMenu->x() + (parentMenu->width() - menu->width()) / 2,
+ parentMenu->y() + (parentMenu->height() - menu->height()) / 2));
}
}
+
QQuickPopupPositioner::reposition();
}
@@ -474,6 +943,36 @@ bool QQuickMenuPrivate::blockInput(QQuickItem *item, const QPointF &point) const
return (cascade && parentMenu && contains(point)) || QQuickPopupPrivate::blockInput(item, point);
}
+/*! \internal
+ QQuickPopupWindow::event() calls this to handle the release event of a
+ menu drag-press-release gesture, because the \a eventPoint does not have
+ a grabber within the popup window. This override finds and activates the
+ appropriate menu item, as if it had been pressed and released.
+ Returns true on success, to indicate that handling \a eventPoint is done.
+ */
+bool QQuickMenuPrivate::handleReleaseWithoutGrab(const QEventPoint &eventPoint)
+{
+ if (!contains(eventPoint.scenePosition()))
+ return false;
+
+ QQuickMenuItem *menuItem = nullptr;
+ // Usually, hover events have occurred, and currentIndex is set.
+ // If not, use eventPoint.position() for picking.
+ if (currentIndex < 0) {
+ auto *list = qobject_cast<QQuickListView *>(contentItem);
+ if (!list)
+ return false;
+ menuItem = qobject_cast<QQuickMenuItem *>(list->itemAt(eventPoint.position().x(), eventPoint.position().y()));
+ } else {
+ menuItem = qobject_cast<QQuickMenuItem *>(itemAt(currentIndex));
+ }
+ if (Q_LIKELY(menuItem)) {
+ menuItem->animateClick();
+ return true;
+ }
+ return false;
+}
+
void QQuickMenuPrivate::onItemHovered()
{
Q_Q(QQuickMenu);
@@ -528,6 +1027,30 @@ void QQuickMenuPrivate::onItemActiveFocusChanged()
setCurrentIndex(indexOfItem, control ? control->focusReason() : Qt::OtherFocusReason);
}
+void QQuickMenuPrivate::updateTextPadding()
+{
+ Q_Q(QQuickMenu);
+ if (!complete)
+ return;
+
+ qreal padding = 0;
+ for (int i = 0; i < q->count(); ++i) {
+ if (const auto menuItem = qobject_cast<QQuickMenuItem *>(itemAt(i)))
+ if (menuItem->isVisible())
+ padding = qMax(padding, menuItem->implicitTextPadding());
+ }
+
+ if (padding == textPadding)
+ return;
+
+ textPadding = padding;
+
+ for (int i = 0; i < q->count(); ++i) {
+ if (const auto menuItem = qobject_cast<QQuickMenuItem *>(itemAt(i)))
+ emit menuItem->textPaddingChanged();
+ }
+}
+
QQuickMenu *QQuickMenuPrivate::currentSubMenu() const
{
if (!currentItem)
@@ -741,11 +1264,17 @@ QQuickMenu::QQuickMenu(QObject *parent)
QQuickMenu::~QQuickMenu()
{
Q_D(QQuickMenu);
- // We have to do this to ensure that the change listeners are removed.
- // It's too late to do this in ~QQuickMenuPrivate, as contentModel has already
- // been destroyed before that is called.
+ qCDebug(lcNativeMenus) << "destroying" << this
+ << "item count:"
+ << d->contentModel->count()
+ << "native item count:" << d->nativeItems.count();
+ // We have to remove items to ensure that our change listeners on the item
+ // are removed. It's too late to do this in ~QQuickMenuPrivate, as
+ // contentModel has already been destroyed before that is called.
+ // Destruction isn't necessary for the QQuickItems themselves, but it is
+ // required for the native menus (see comment in removeItem()).
while (d->contentModel->count() > 0)
- d->removeItem(0, d->itemAt(0));
+ d->removeItem(0, d->itemAt(0), QQuickMenuPrivate::DestructionPolicy::Destroy);
if (d->contentItem) {
QQuickItemPrivate::get(d->contentItem)->removeItemChangeListener(d, QQuickItemPrivate::Children);
@@ -797,8 +1326,9 @@ void QQuickMenu::insertItem(int index, QQuickItem *item)
if (oldIndex != -1) {
if (oldIndex < index)
--index;
- if (oldIndex != index)
+ if (oldIndex != index) {
d->moveItem(oldIndex, index);
+ }
} else {
d->insertItem(index, item);
}
@@ -838,8 +1368,7 @@ void QQuickMenu::removeItem(QQuickItem *item)
if (index == -1)
return;
- d->removeItem(index, item);
- item->deleteLater();
+ d->removeItem(index, item, QQuickMenuPrivate::DestructionPolicy::Destroy);
}
/*!
@@ -953,6 +1482,7 @@ QQuickMenu *QQuickMenu::takeMenu(int index)
d->removeItem(index, item);
item->deleteLater();
+
return subMenu;
}
@@ -966,11 +1496,18 @@ QQuickMenu *QQuickMenu::takeMenu(int index)
QQuickAction *QQuickMenu::actionAt(int index) const
{
Q_D(const QQuickMenu);
- QQuickAbstractButton *item = qobject_cast<QQuickAbstractButton *>(d->itemAt(index));
- if (!item)
- return nullptr;
+ if (!const_cast<QQuickMenuPrivate *>(d)->maybeNativeHandle()) {
+ QQuickAbstractButton *item = qobject_cast<QQuickAbstractButton *>(d->itemAt(index));
+ if (!item)
+ return nullptr;
- return item->action();
+ return item->action();
+ } else {
+ if (index < 0 || index >= d->nativeItems.size())
+ return nullptr;
+
+ return d->nativeItems.at(index)->action();
+ }
}
/*!
@@ -1049,6 +1586,43 @@ QQuickAction *QQuickMenu::takeAction(int index)
return action;
}
+bool QQuickMenu::isVisible() const
+{
+ Q_D(const QQuickMenu);
+ if (d->maybeNativeHandle())
+ return d->visible;
+ return QQuickPopup::isVisible();
+}
+
+void QQuickMenu::setVisible(bool visible)
+{
+ Q_D(QQuickMenu);
+ if (visible == d->visible)
+ return;
+ if (visible && !parentItem()) {
+ qmlWarning(this) << "cannot show menu: parent is null";
+ return;
+ }
+
+ if (visible && ((d->useNativeMenu() && !d->maybeNativeHandle())
+ || (!d->useNativeMenu() && d->maybeNativeHandle()))) {
+ // We've been made visible, and our actual native state doesn't match our requested state,
+ // which means AA_DontUseNativeMenuWindows was set while we were visible or had a parent.
+ // Try to sync our state again now that we're about to be re-opened.
+ qCDebug(lcNativeMenus) << "setVisible called - useNativeMenu:" << d->useNativeMenu()
+ << "maybeNativeHandle:" << d->maybeNativeHandle();
+ d->syncWithUseNativeMenu();
+ }
+ if (d->maybeNativeHandle()) {
+ d->setNativeMenuVisible(visible);
+ return;
+ }
+
+ // Either the native menu wasn't wanted, or it couldn't be created;
+ // show the non-native menu.
+ QQuickPopup::setVisible(visible);
+}
+
/*!
\qmlproperty model QtQuick.Controls::Menu::contentModel
\readonly
@@ -1124,6 +1698,8 @@ void QQuickMenu::setTitle(const QString &title)
if (title == d->title)
return;
d->title = title;
+ if (d->handle)
+ d->handle->setText(title);
emit titleChanged(title);
}
@@ -1139,6 +1715,8 @@ void QQuickMenu::setTitle(const QString &title)
\include qquickicon.qdocinc grouped-properties
+ \include qquickmenu.qdocinc non-native-only-property
+
\sa AbstractButton::text, AbstractButton::display, {Icons in Qt Quick Controls}
*/
@@ -1170,6 +1748,8 @@ void QQuickMenu::setIcon(const QQuickIcon &icon)
\note Changing the value of the property has no effect while the menu is open.
+ \include qquickmenu.qdocinc non-native-only-property
+
\sa overlap
*/
bool QQuickMenu::cascade() const
@@ -1210,6 +1790,8 @@ void QQuickMenu::resetCascade()
\note Changing the value of the property has no effect while the menu is open.
+ \include qquickmenu.qdocinc non-native-only-property
+
\sa cascade
*/
qreal QQuickMenu::overlap() const
@@ -1242,6 +1824,9 @@ void QQuickMenu::setOverlap(qreal overlap)
}
\endcode
+ \note delegates will only be visible when using a \l {Native Menus}
+ {non-native Menu}.
+
\sa Action
*/
QQmlComponent *QQuickMenu::delegate() const
@@ -1268,6 +1853,8 @@ void QQuickMenu::setDelegate(QQmlComponent *delegate)
Menu items can be highlighted by mouse hover or keyboard navigation.
+ \include qquickmenu.qdocinc non-native-only-property
+
\sa MenuItem::highlighted
*/
int QQuickMenu::currentIndex() const
@@ -1434,9 +2021,10 @@ void QQuickMenu::popup(QQmlV4FunctionPtr args)
Closes all menus in the hierarchy that this menu belongs to.
- \note Unlike \l {Popup::}{close()} that only closes a menu and its sub-menus,
- \c dismiss() closes the whole hierarchy of menus, including the parent menus.
- In practice, \c close() is suitable e.g. for implementing navigation in a
+ \note Unlike \l {Popup::}{close()} that only closes a menu and its
+ sub-menus (when using \l {Native Menus}{non-native menus}), \c dismiss()
+ closes the whole hierarchy of menus, including the parent menus. In
+ practice, \c close() is suitable e.g. for implementing navigation in a
hierarchy of menus, and \c dismiss() is the appropriate method for closing
the whole hierarchy of menus.
@@ -1456,6 +2044,8 @@ void QQuickMenu::componentComplete()
Q_D(QQuickMenu);
QQuickPopup::componentComplete();
d->resizeItems();
+ d->updateTextPadding();
+ d->syncWithUseNativeMenu();
}
void QQuickMenu::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
@@ -1480,12 +2070,16 @@ void QQuickMenu::itemChange(QQuickItem::ItemChange change, const QQuickItem::Ite
Q_D(QQuickMenu);
QQuickPopup::itemChange(change, data);
- if (change == QQuickItem::ItemVisibleHasChanged) {
+ switch (change) {
+ case QQuickItem::ItemVisibleHasChanged:
if (!data.boolValue && d->cascade) {
// Ensure that when the menu isn't visible, there's no current item
// the next time it's opened.
d->setCurrentIndex(-1, Qt::OtherFocusReason);
}
+ break;
+ default:
+ break;
}
}
diff --git a/src/quicktemplates/qquickmenu_p.h b/src/quicktemplates/qquickmenu_p.h
index 0ff8a121ac..ed08537fdb 100644
--- a/src/quicktemplates/qquickmenu_p.h
+++ b/src/quicktemplates/qquickmenu_p.h
@@ -97,6 +97,9 @@ public:
Q_REVISION(2, 3) Q_INVOKABLE void removeAction(QQuickAction *action);
Q_REVISION(2, 3) Q_INVOKABLE QQuickAction *takeAction(int index);
+ bool isVisible() const override;
+ void setVisible(bool visible) override;
+
void popup(QQuickItem *menuItem = nullptr);
void popup(const QPointF &pos, QQuickItem *menuItem = nullptr);
diff --git a/src/quicktemplates/qquickmenu_p_p.h b/src/quicktemplates/qquickmenu_p_p.h
index 552f35794a..e3003b7d55 100644
--- a/src/quicktemplates/qquickmenu_p_p.h
+++ b/src/quicktemplates/qquickmenu_p_p.h
@@ -18,6 +18,8 @@
#include <QtCore/qlist.h>
#include <QtCore/qpointer.h>
+#include <QtGui/qpa/qplatformmenu.h>
+
#include <QtQuickTemplates2/private/qquickmenu_p.h>
#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
@@ -27,6 +29,8 @@ class QQuickAction;
class QQmlComponent;
class QQmlObjectModel;
class QQuickMenuItem;
+class QQuickNativeMenuItem;
+class QQuickMenuBar;
class Q_QUICKTEMPLATES2_EXPORT QQuickMenuPrivate : public QQuickPopupPrivate
{
@@ -42,10 +46,33 @@ public:
void init();
+ QPlatformMenu *nativeHandle();
+ QPlatformMenu *maybeNativeHandle() const;
+ QQuickMenu *rootMenu() const;
+ bool useNativeMenu() const;
+ bool createNativeMenu();
+ void removeNativeMenu();
+ void syncWithNativeMenu();
+ void syncWithUseNativeMenu();
+ static void recursivelyDestroyNativeSubMenus(QQuickMenu *menu);
+ void setNativeMenuVisible(bool visible);
+
QQuickItem *itemAt(int index) const;
void insertItem(int index, QQuickItem *item);
+ void maybeCreateAndInsertNativeItem(int index, QQuickItem *item);
void moveItem(int from, int to);
- void removeItem(int index, QQuickItem *item);
+ enum class DestructionPolicy {
+ Destroy,
+ DoNotDestroy
+ };
+ void removeItem(int index, QQuickItem *item,
+ DestructionPolicy destructionPolicy = DestructionPolicy::DoNotDestroy);
+ void removeNativeItem(int index);
+ void resetNativeData();
+
+ static void recursivelyCreateNativeMenuItems(QQuickMenu *menu);
+
+ void printContentModelItems() const;
QQuickItem *beginCreateItem();
void completeCreateItem();
@@ -66,10 +93,12 @@ public:
bool prepareEnterTransition() override;
bool prepareExitTransition() override;
bool blockInput(QQuickItem *item, const QPointF &point) const override;
+ bool handleReleaseWithoutGrab(const QEventPoint &eventPoint) override;
void onItemHovered();
void onItemTriggered();
void onItemActiveFocusChanged();
+ void updateTextPadding();
QQuickMenu *currentSubMenu() const;
void setParentMenu(QQuickMenu *parent);
@@ -94,9 +123,11 @@ public:
QPalette defaultPalette() const override;
bool cascade = false;
+ bool triedToCreateNativeMenu = false;
int hoverTimer = 0;
int currentIndex = -1;
qreal overlap = 0;
+ qreal textPadding = 0;
QPointer<QQuickMenu> parentMenu;
QPointer<QQuickMenuItem> currentItem;
QQuickItem *contentItem = nullptr; // TODO: cleanup
@@ -105,6 +136,12 @@ public:
QQmlComponent *delegate = nullptr;
QString title;
QQuickIcon icon;
+
+ // For native menu support.
+ std::unique_ptr<QPlatformMenu> handle = nullptr;
+ QList<QQuickNativeMenuItem *> nativeItems;
+ QPointer<QQuickMenuBar> menuBar;
+ qreal lastDevicePixelRatio = 0;
};
QT_END_NAMESPACE
diff --git a/src/quicktemplates/qquickmenubar.cpp b/src/quicktemplates/qquickmenubar.cpp
index 62c7680d0d..5bc6995670 100644
--- a/src/quicktemplates/qquickmenubar.cpp
+++ b/src/quicktemplates/qquickmenubar.cpp
@@ -42,16 +42,27 @@ QT_BEGIN_NAMESPACE
\l {removeMenu}{remove}, and \l {takeMenu}{take} menus dynamically. The
menus in a menu bar can be accessed using \l menuAt().
+ \note Since Qt 6.8, MenuBar is implemented as a native menu bar on \macos. As a
+ result, all Menus, MenuItems and MenuBarItems within a MenuBar will also be native.
+ While this has the advantage that everything will look native, it also comes with the
+ disadvantage that the delegates set on the mentioned controls will not be used
+ for rendering.
+ If a native MenuBar is not wanted, you can set
+ \l {Qt::AA_DontUseNativeMenuBar}{QGuiApplication::setAttribute(Qt::AA_DontUseNativeMenuBar)}
+ to disable it.
+
\sa {Customizing MenuBar}, Menu, MenuBarItem, {Menu Controls},
{Focus Management in Qt Quick Controls}
*/
-QQuickItem *QQuickMenuBarPrivate::beginCreateItem(QQuickMenu *menu)
+Q_LOGGING_CATEGORY(lcMenuBar, "qt.quick.controls.menubar")
+
+static const char* kCreatedFromDelegate = "_qt_createdFromDelegate";
+
+QQuickItem *QQuickMenuBarPrivate::createItemFromDelegate()
{
Q_Q(QQuickMenuBar);
- if (!delegate)
- return nullptr;
-
+ Q_ASSERT(delegate);
QQmlContext *context = delegate->creationContext();
if (!context)
context = qmlContext(q);
@@ -63,45 +74,94 @@ QQuickItem *QQuickMenuBarPrivate::beginCreateItem(QQuickMenu *menu)
return nullptr;
}
- if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item))
- menuBarItem->setMenu(menu);
- item->setParentItem(q);
QQml_setParent_noEvent(item, q);
+ delegate->completeCreate();
return item;
}
-void QQuickMenuBarPrivate::completeCreateItem()
+QQuickMenuBarItem *QQuickMenuBarPrivate::createMenuBarItem(QQuickMenu *menu)
{
- if (!delegate)
- return;
+ Q_Q(QQuickMenuBar);
- delegate->completeCreate();
+ QQuickMenuBarItem *menuBarItem = nullptr;
+ if (delegate) {
+ QQuickItem *item = createItemFromDelegate();
+ menuBarItem = qobject_cast<QQuickMenuBarItem *>(item);
+ if (!menuBarItem) {
+ qmlWarning(q) << "cannot insert menu: the delegate is not a MenuBarItem.";
+ delete item;
+ }
+ }
+
+ if (!menuBarItem) {
+ // When we fail to create a delegate item, create a hidden placeholder
+ // instead. This is needed, since we store the menus inside the container
+ // using MenuBarItem. And without a MenuBarItem, we would therefore lose
+ // the menu, even if the delegate is changed later.
+ qCDebug(lcMenuBar) << "creating hidden placeholder MenuBarItem for:" << menu->title();
+ menuBarItem = new QQuickMenuBarItem(q);
+ menuBarItem->setParentItem(q);
+ menuBarItem->setVisible(false);
+ }
+
+ menuBarItem->setMenu(menu);
+
+ // Tag the menuBarItem, so that we know which container items to change if the
+ // delegate is changed. This is needed since you can add MenuBarItems directly
+ // to the menu bar, which should not change when the delegate changes.
+ menuBarItem->setProperty(kCreatedFromDelegate, true);
+
+ return menuBarItem;
}
-QQuickItem *QQuickMenuBarPrivate::createItem(QQuickMenu *menu)
+void QQuickMenuBarPrivate::openCurrentMenu()
{
- QQuickItem *item = beginCreateItem(menu);
- completeCreateItem();
- return item;
+ if (!currentItem || currentMenuOpen)
+ return;
+ QQuickMenu *menu = currentItem->menu();
+ if (!menu || menu->isOpened())
+ return;
+
+#ifdef Q_OS_MACOS
+ // On macOS, the menu should open underneath the MenuBar
+ Q_Q(QQuickMenuBar);
+ const QPointF posInParentItem = q->mapToItem(currentItem, {currentItem->x(), q->height()});
+#else
+ // On other platforms, it should open underneath the MenuBarItem
+ const QPointF posInParentItem{0, currentItem->y() + currentItem->height()};
+#endif
+
+ // Store explicit if the current menu is logically supposed to be open.
+ // menu->isVisible() is async when using top-level menus, and will not become
+ // "true" before the menu is actually shown by the OS. This will cause us to
+ // lose track of if a menu is (supposed to be) open, if relying on menu->isVisible().
+ currentMenuOpen = true;
+
+ // The position should be the coordinate system of the parent item. Note that
+ // the parentItem() of a menu will be the MenuBarItem (currentItem), and not the
+ // MenuBar (even if parent() usually points to the MenuBar).
+ menu->popup(posInParentItem);
}
-void QQuickMenuBarPrivate::toggleCurrentMenu(bool visible, bool activate)
+void QQuickMenuBarPrivate::closeCurrentMenu()
{
- if (!currentItem || visible == popupMode)
+ if (!currentItem || !currentMenuOpen)
return;
-
+ currentMenuOpen = false;
QQuickMenu *menu = currentItem->menu();
+ QScopedValueRollback triggerRollback(closingCurrentMenu, true);
+ menu->dismiss();
+}
- triggering = true;
- popupMode = visible;
- if (menu)
- menu->setVisible(visible);
- if (!visible)
- currentItem->forceActiveFocus();
- else if (menu && activate)
- menu->setCurrentIndex(0);
- triggering = false;
+void QQuickMenuBarPrivate::activateMenuItem(int index)
+{
+ if (!currentItem)
+ return;
+ QQuickMenu *menu = currentItem->menu();
+ if (!menu)
+ return;
+ menu->setCurrentIndex(index);
}
void QQuickMenuBarPrivate::activateItem(QQuickMenuBarItem *item)
@@ -109,23 +169,20 @@ void QQuickMenuBarPrivate::activateItem(QQuickMenuBarItem *item)
if (currentItem == item)
return;
+ const bool stayOpen = currentMenuOpen;
+
if (currentItem) {
currentItem->setHighlighted(false);
- if (popupMode) {
- if (QQuickMenu *menu = currentItem->menu())
- menu->dismiss();
- }
- }
-
- if (item) {
- item->setHighlighted(true);
- if (popupMode) {
- if (QQuickMenu *menu = item->menu())
- menu->open();
- }
+ closeCurrentMenu();
}
currentItem = item;
+
+ if (currentItem) {
+ currentItem->setHighlighted(true);
+ if (stayOpen)
+ openCurrentMenu();
+ }
}
void QQuickMenuBarPrivate::activateNextItem()
@@ -162,19 +219,34 @@ void QQuickMenuBarPrivate::onItemTriggered()
return;
if (item == currentItem) {
- toggleCurrentMenu(!popupMode, false);
+ if (currentMenuOpen) {
+ closeCurrentMenu();
+ currentItem->forceActiveFocus();
+ } else {
+ openCurrentMenu();
+ }
} else {
- popupMode = true;
activateItem(item);
+ openCurrentMenu();
}
}
-void QQuickMenuBarPrivate::onMenuAboutToHide()
+void QQuickMenuBarPrivate::onMenuAboutToHide(QQuickMenu *menu)
{
- if (triggering || !currentItem || !currentItem->isHighlighted())
+ if (closingCurrentMenu) {
+ // We only react on a menu closing if it's
+ // initiated from outside of QQuickMenuBar.
+ return;
+ }
+
+ if (!currentItem || currentItem->menu() != menu)
+ return;
+
+ currentMenuOpen = false;
+
+ if (!currentItem->isHighlighted() || currentItem->isHovered())
return;
- popupMode = false;
activateItem(nullptr);
}
@@ -220,14 +292,32 @@ void QQuickMenuBarPrivate::itemImplicitHeightChanged(QQuickItem *item)
void QQuickMenuBarPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
{
- QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object);
- if (QQuickMenu *menu = qobject_cast<QQuickMenu *>(obj))
- obj = QQuickMenuBarPrivate::get(menuBar)->createItem(menu);
+ auto menuBar = static_cast<QQuickMenuBar *>(prop->object);
+ auto menuBarPriv = QQuickMenuBarPrivate::get(menuBar);
+
+ if (auto *menu = qobject_cast<QQuickMenu *>(obj)) {
+ QQuickMenuBarItem *delegateItem = menuBarPriv->createMenuBarItem(menu);
+ menuBarPriv->insertMenu(menuBar->count(), menu, delegateItem);
+ QQuickContainerPrivate::contentData_append(prop, delegateItem);
+ return;
+ }
+
+ if (auto *menuBarItem = qobject_cast<QQuickMenuBarItem *>(obj)) {
+ menuBarPriv->insertMenu(menuBar->count(), menuBarItem->menu(), menuBarItem);
+ QQuickContainerPrivate::contentData_append(prop, menuBarItem);
+ return;
+ }
+
QQuickContainerPrivate::contentData_append(prop, obj);
}
void QQuickMenuBarPrivate::menus_append(QQmlListProperty<QQuickMenu> *prop, QQuickMenu *obj)
{
+ // This function is only called if the application assigns a list of menus
+ // directly to the 'menus' property. Otherwise, contentData_append is used.
+ // Since the functions belonging to the 'menus' list anyway returns data from
+ // the menuBar, calls such as "menuBar.menus.length" works as expected
+ // regardless of how the menus were added.
QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object);
menuBar->addMenu(obj);
}
@@ -255,6 +345,283 @@ QPalette QQuickMenuBarPrivate::defaultPalette() const
return QQuickTheme::palette(QQuickTheme::MenuBar);
}
+QWindow* QQuickMenuBarPrivate::window() const
+{
+ Q_Q(const QQuickMenuBar);
+ QObject *obj = q->parent();
+ while (obj) {
+ if (QWindow *window = qobject_cast<QWindow *>(obj))
+ return window;
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj);
+ if (item && item->window())
+ return item->window();
+ obj = obj->parent();
+ }
+ return nullptr;
+}
+
+int QQuickMenuBarPrivate::menuIndex(QQuickMenu *menu) const
+{
+ Q_Q(const QQuickMenuBar);
+ for (int i = 0; i < q->count(); ++i) {
+ if (q->menuAt(i) == menu)
+ return i;
+ }
+
+ return -1;
+}
+
+QPlatformMenuBar* QQuickMenuBarPrivate::nativeHandle() const
+{
+ return handle.get();
+}
+
+void QQuickMenuBarPrivate::insertNativeMenu(QQuickMenu *menu)
+{
+ Q_Q(QQuickMenuBar);
+ Q_ASSERT(handle);
+ Q_ASSERT(menu);
+
+ QPlatformMenu *insertBeforeHandle = nullptr;
+
+ // This function assumes that the QQuickMenuBarItem that corresponds to \a menu
+ // has already been added to the container at the correct index. So we search for
+ // it, to determine where to insert it in the native menubar. Since the QPA API
+ // expects a pointer to the QPlatformMenu that comes after it, we need to search
+ // for that one as well, since some MenuBarItems in the container can be hidden.
+ bool foundInContainer = false;
+ for (int i = 0; i < q->count(); ++i) {
+ if (q->menuAt(i) != menu)
+ continue;
+ foundInContainer = true;
+
+ for (int j = i + 1; j < q->count(); ++j) {
+ insertBeforeHandle = QQuickMenuPrivate::get(q->menuAt(j))->maybeNativeHandle();
+ if (insertBeforeHandle)
+ break;
+ }
+
+ break;
+ }
+
+ Q_ASSERT(foundInContainer);
+ QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu);
+ if (QPlatformMenu *menuHandle = menuPrivate->nativeHandle()) {
+ qCDebug(lcMenuBar) << "insert native menu:" << menu->title() << menuHandle << "before:" << insertBeforeHandle;
+ handle->insertMenu(menuPrivate->nativeHandle(), insertBeforeHandle);
+ } else {
+ qmlWarning(q) << "failed to create native menu for:" << menu->title();
+ }
+}
+
+void QQuickMenuBarPrivate::removeNativeMenu(QQuickMenu *menu)
+{
+ Q_ASSERT(handle);
+ Q_ASSERT(menu);
+
+ QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu);
+ if (!menuPrivate->maybeNativeHandle())
+ return;
+
+ qCDebug(lcMenuBar) << "remove native menu:" << menu << menu->title();
+ handle->removeMenu(menuPrivate->nativeHandle());
+ menuPrivate->removeNativeMenu();
+}
+
+void QQuickMenuBarPrivate::syncMenuBarItemVisibilty(QQuickMenuBarItem *menuBarItem)
+{
+ if (!handle) {
+ // We only need to update visibility on native menu bar items
+ return;
+ }
+
+ QQuickMenu *menu = menuBarItem->menu();
+ if (!menu)
+ return;
+ QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu);
+
+ if (menuBarItem->isVisible()) {
+ Q_ASSERT(!menuPrivate->maybeNativeHandle());
+ insertNativeMenu(menu);
+ } else {
+ if (menuPrivate->maybeNativeHandle())
+ removeNativeMenu(menu);
+ }
+}
+
+void QQuickMenuBarPrivate::insertMenu(int index, QQuickMenu *menu, QQuickMenuBarItem *menuBarItem)
+{
+ Q_Q(QQuickMenuBar);
+ if (!menu) {
+ qmlWarning(q) << "cannot insert menu: menu is null.";
+ return;
+ }
+
+ auto menuPrivate = QQuickMenuPrivate::get(menu);
+ menuPrivate->menuBar = q;
+
+ QObject::connect(menuBarItem, &QQuickMenuBarItem::visibleChanged, [this, menuBarItem]{
+ syncMenuBarItemVisibilty(menuBarItem);
+ });
+
+ // Always insert menu into the container, even when using a native
+ // menubar, so that container API such as 'count' and 'itemAt'
+ // continues to work as expected.
+ q->insertItem(index, menuBarItem);
+
+ // Create or remove a native (QPlatformMenu) menu. Note that we should only create
+ // a native menu if it's supposed to be visible in the menu bar.
+ if (menuBarItem->isVisible()) {
+ if (handle)
+ insertNativeMenu(menu);
+ } else {
+ if (menuPrivate->maybeNativeHandle()) {
+ // If the menu was added from an explicit call to addMenu(m), it will have been
+ // created before we enter here. And in that case, QQuickMenuBar::useNativeMenu(m)
+ // was never called, and a QPlatformMenu might have been created for it. In that
+ // case, we remove it again now, since the menu is not supposed to be visible in
+ // the menu bar.
+ menuPrivate->removeNativeMenu();
+ }
+ }
+}
+
+QQuickMenu *QQuickMenuBarPrivate::takeMenu(int index)
+{
+ Q_Q(QQuickMenuBar);
+ QQuickItem *item = q->itemAt(index);
+ Q_ASSERT(item);
+ QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item);
+ if (!menuBarItem) {
+ qmlWarning(q) << "cannot take/remove menu: item at index " << index << " is not a MenuBarItem.";
+ return nullptr;
+ }
+ QQuickMenu *menu = menuBarItem->menu();
+ if (!menu) {
+ qmlWarning(q) << "cannot take/remove menu: MenuBarItem.menu at index " << index << " is null.";
+ return nullptr;
+ }
+
+ // Dismiss the menu if it's open. Otherwise, when we now remove it from
+ // the menubar, it will stay open without the user being able to dismiss
+ // it (at least if it's non-native).
+ menu->dismiss();
+
+ if (item == currentItem)
+ activateItem(nullptr);
+
+ if (QQuickMenuPrivate::get(menu)->maybeNativeHandle())
+ removeNativeMenu(menu);
+
+ removeItem(index, item);
+
+ // Delete the MenuBarItem. This will also cause the menu to be deleted by
+ // the garbage collector, unless other QML references are being held to it.
+ // Note: We might consider leaving it to the garbage collector to also
+ // delete the MenuBarItem in the future.
+ item->deleteLater();
+
+ QQuickMenuPrivate::get(menu)->menuBar = nullptr;
+ menuBarItem->disconnect(q);
+
+ return menu;
+}
+
+bool QQuickMenuBarPrivate::useNativeMenuBar() const
+{
+ // We current only use native menu bars on macOS. Especially, the
+ // QPA menu bar for Windows is old and unused, and looks broken and non-native.
+#ifdef Q_OS_MACOS
+ return !QCoreApplication::testAttribute(Qt::AA_DontUseNativeMenuBar);
+#else
+ return false;
+#endif
+}
+
+bool QQuickMenuBarPrivate::useNativeMenu(const QQuickMenu *menu) const
+{
+ Q_Q(const QQuickMenuBar);
+ if (!useNativeMenuBar())
+ return false;
+
+ // Since we cannot hide a QPlatformMenu, we have to avoid
+ // creating it if it shouldn't be visible in the menu bar.
+ for (int i = 0; i < q->count(); ++i) {
+ if (q->menuAt(i) == menu)
+ return itemAt(i)->isVisible();
+ }
+
+ return true;
+}
+
+void QQuickMenuBarPrivate::syncNativeMenuBarVisible()
+{
+ Q_Q(QQuickMenuBar);
+ if (!componentComplete)
+ return;
+
+ const bool shouldBeVisible = q->isVisible() && useNativeMenuBar();
+ qCDebug(lcMenuBar) << "syncNativeMenuBarVisible called - q->isVisible()" << q->isVisible()
+ << "useNativeMenuBar()" << useNativeMenuBar() << "handle" << handle.get();
+ if (shouldBeVisible && !handle)
+ createNativeMenuBar();
+ else if (!shouldBeVisible && handle)
+ removeNativeMenuBar();
+}
+
+void QQuickMenuBarPrivate::createNativeMenuBar()
+{
+ Q_Q(QQuickMenuBar);
+ Q_ASSERT(!handle);
+ qCDebug(lcMenuBar) << "creating native menubar";
+
+ handle.reset(QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar());
+ if (!handle) {
+ qCDebug(lcMenuBar) << "QPlatformTheme failed to create a QPlatformMenuBar!";
+ return;
+ }
+
+ handle->handleReparent(window());
+ qCDebug(lcMenuBar) << "native menubar parented to window:" << handle->parentWindow();
+
+ // Add all the native menus. We need to do this right-to-left
+ // because of the QPA API (insertBefore).
+ for (int i = q->count() - 1; i >= 0; --i) {
+ if (QQuickMenu *menu = q->menuAt(i)) {
+ if (useNativeMenu(menu))
+ insertNativeMenu(menu);
+ }
+ }
+
+ // Hide the non-native menubar and set it's height to 0. The
+ // latter will cause a relayout to happen in ApplicationWindow
+ // which effectively removes the menubar from the contentItem.
+ setCulled(true);
+ q->setHeight(0);
+}
+
+void QQuickMenuBarPrivate::removeNativeMenuBar()
+{
+ Q_Q(QQuickMenuBar);
+ Q_ASSERT(handle);
+ qCDebug(lcMenuBar) << "removing native menubar";
+
+ // Remove all native menus.
+ for (int i = 0; i < q->count(); ++i) {
+ if (QQuickMenu *menu = q->menuAt(i))
+ removeNativeMenu(menu);
+ }
+
+ // Delete the menubar
+ handle.reset();
+
+ // Show the non-native menubar and reset it's height. The
+ // latter will cause a relayout to happen in ApplicationWindow
+ // which will effectively add the menubar to the contentItem.
+ setCulled(false);
+ q->resetHeight();
+}
+
QQuickMenuBar::QQuickMenuBar(QQuickItem *parent)
: QQuickContainer(*(new QQuickMenuBarPrivate), parent)
{
@@ -264,6 +631,13 @@ QQuickMenuBar::QQuickMenuBar(QQuickItem *parent)
setFocusPolicy(Qt::ClickFocus);
}
+QQuickMenuBar::~QQuickMenuBar()
+{
+ Q_D(QQuickMenuBar);
+ if (d->handle)
+ d->removeNativeMenuBar();
+}
+
/*!
\qmlproperty Component QtQuick.Controls::MenuBar::delegate
@@ -285,6 +659,21 @@ void QQuickMenuBar::setDelegate(QQmlComponent *delegate)
return;
d->delegate = delegate;
+
+ for (int i = count() - 1; i >= 0; --i) {
+ auto item = itemAt(i);
+ if (!item->property(kCreatedFromDelegate).toBool())
+ continue;
+
+ QQuickMenuBarItem *menuBarItem = static_cast<QQuickMenuBarItem *>(item);
+ if (QQuickMenu *menu = menuBarItem->menu()) {
+ removeMenu(menu);
+ d->insertMenu(i, menu, d->createMenuBarItem(menu));
+ } else {
+ removeItem(menuBarItem);
+ }
+ }
+
emit delegateChanged();
}
@@ -310,7 +699,12 @@ QQuickMenu *QQuickMenuBar::menuAt(int index) const
void QQuickMenuBar::addMenu(QQuickMenu *menu)
{
Q_D(QQuickMenuBar);
- addItem(d->createItem(menu));
+ if (d->menuIndex(menu) >= 0) {
+ qmlWarning(this) << "cannot add menu: '" << menu->title() << "' is already in the MenuBar.";
+ return;
+ }
+
+ d->insertMenu(count(), menu, d->createMenuBarItem(menu));
}
/*!
@@ -321,54 +715,52 @@ void QQuickMenuBar::addMenu(QQuickMenu *menu)
void QQuickMenuBar::insertMenu(int index, QQuickMenu *menu)
{
Q_D(QQuickMenuBar);
- insertItem(index, d->createItem(menu));
+ if (d->menuIndex(menu) >= 0) {
+ qmlWarning(this) << "cannot insert menu: '" << menu->title() << "' is already in the MenuBar.";
+ return;
+ }
+
+ d->insertMenu(index, menu, d->createMenuBarItem(menu));
}
/*!
\qmlmethod void QtQuick.Controls::MenuBar::removeMenu(Menu menu)
- Removes and destroys the specified \a menu.
+ Removes specified \a menu. If the menu is \l {QQuickMenu::popup(QQmlV4Function *)}{open},
+ it will first be \l {QQuickMenu::dismiss()}{dismissed.}
+ The \a menu will eventually be deleted by the garbage collector when the
+ application no longer holds any QML references to it.
*/
void QQuickMenuBar::removeMenu(QQuickMenu *menu)
{
Q_D(QQuickMenuBar);
- if (!menu)
+ const int index = d->menuIndex(menu);
+ if (index < 0) {
+ qmlWarning(this) << "cannot remove menu: '" << menu->title() << "' is not in the MenuBar.";
return;
-
- const int count = d->contentModel->count();
- for (int i = 0; i < count; ++i) {
- QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(itemAt(i));
- if (!item || item->menu() != menu)
- continue;
-
- removeItem(item);
- break;
}
- menu->deleteLater();
+ d->takeMenu(index);
}
/*!
\qmlmethod Menu QtQuick.Controls::MenuBar::takeMenu(int index)
- Removes and returns the menu at \a index.
-
- \note The ownership of the item is transferred to the caller.
+ Removes and returns the menu at \a index. If the menu is
+ \l {QQuickMenu::popup(QQmlV4Function *)}{open}, it will first be
+ \l {QQuickMenu::dismiss()}{dismissed.}
+ The menu will eventually be deleted by the garbage collector when the
+ application no longer holds any QML references to it.
*/
QQuickMenu *QQuickMenuBar::takeMenu(int index)
{
Q_D(QQuickMenuBar);
- QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(itemAt(index));
- if (!item)
- return nullptr;
-
- QQuickMenu *menu = item->menu();
- if (!menu)
+ if (index < 0 || index > count() - 1) {
+ qmlWarning(this) << "index out of range: " << index;
return nullptr;
+ }
- d->removeItem(index, item);
- item->deleteLater();
- return menu;
+ return d->takeMenu(index);
}
/*!
@@ -488,11 +880,12 @@ void QQuickMenuBar::keyPressEvent(QKeyEvent *event)
switch (event->key()) {
case Qt::Key_Up:
- d->toggleCurrentMenu(false, false);
+ d->closeCurrentMenu();
break;
case Qt::Key_Down:
- d->toggleCurrentMenu(true, true);
+ d->openCurrentMenu();
+ d->activateMenuItem(0);
break;
case Qt::Key_Left:
@@ -517,7 +910,8 @@ void QQuickMenuBar::keyPressEvent(QKeyEvent *event)
if (auto *item = qobject_cast<QQuickMenuBarItem *>(d->itemAt(i))) {
if (item->shortcut() == mnemonic) {
d->activateItem(item);
- d->toggleCurrentMenu(true, true);
+ d->openCurrentMenu();
+ d->activateMenuItem(0);
}
}
}
@@ -550,7 +944,7 @@ void QQuickMenuBar::hoverLeaveEvent(QHoverEvent *event)
{
Q_D(QQuickMenuBar);
QQuickContainer::hoverLeaveEvent(event);
- if (!d->popupMode && d->currentItem)
+ if (!d->currentMenuOpen && d->currentItem)
d->activateItem(nullptr);
}
@@ -573,6 +967,10 @@ void QQuickMenuBar::itemChange(QQuickItem::ItemChange change, const QQuickItem::
d->windowContentItem->installEventFilter(this);
}
break;
+ case ItemVisibleHasChanged:
+ qCDebug(lcMenuBar) << "visibility of" << this << "changed to" << isVisible();
+ d->syncNativeMenuBarVisible();
+ break;
default:
break;
}
@@ -587,7 +985,7 @@ void QQuickMenuBar::itemAdded(int index, QQuickItem *item)
QObjectPrivate::connect(menuBarItem, &QQuickControl::hoveredChanged, d, &QQuickMenuBarPrivate::onItemHovered);
QObjectPrivate::connect(menuBarItem, &QQuickMenuBarItem::triggered, d, &QQuickMenuBarPrivate::onItemTriggered);
if (QQuickMenu *menu = menuBarItem->menu())
- QObjectPrivate::connect(menu, &QQuickPopup::aboutToHide, d, &QQuickMenuBarPrivate::onMenuAboutToHide);
+ connect(menu, &QQuickPopup::aboutToHide, [this, menu]{ d_func()->onMenuAboutToHide(menu); });
}
d->updateImplicitContentSize();
emit menusChanged();
@@ -608,12 +1006,19 @@ void QQuickMenuBar::itemRemoved(int index, QQuickItem *item)
QObjectPrivate::disconnect(menuBarItem, &QQuickControl::hoveredChanged, d, &QQuickMenuBarPrivate::onItemHovered);
QObjectPrivate::disconnect(menuBarItem, &QQuickMenuBarItem::triggered, d, &QQuickMenuBarPrivate::onItemTriggered);
if (QQuickMenu *menu = menuBarItem->menu())
- QObjectPrivate::disconnect(menu, &QQuickPopup::aboutToHide, d, &QQuickMenuBarPrivate::onMenuAboutToHide);
+ menu->disconnect(this);
}
d->updateImplicitContentSize();
emit menusChanged();
}
+void QQuickMenuBar::componentComplete()
+{
+ Q_D(QQuickMenuBar);
+ QQuickContainer::componentComplete();
+ d->syncNativeMenuBarVisible();
+}
+
QFont QQuickMenuBar::defaultFont() const
{
return QQuickTheme::font(QQuickTheme::MenuBar);
diff --git a/src/quicktemplates/qquickmenubar_p.h b/src/quicktemplates/qquickmenubar_p.h
index daa6bf362b..f053ff6b49 100644
--- a/src/quicktemplates/qquickmenubar_p.h
+++ b/src/quicktemplates/qquickmenubar_p.h
@@ -35,6 +35,7 @@ class Q_QUICKTEMPLATES2_EXPORT QQuickMenuBar : public QQuickContainer
public:
explicit QQuickMenuBar(QQuickItem *parent = nullptr);
+ ~QQuickMenuBar() override;
QQmlComponent *delegate() const;
void setDelegate(QQmlComponent *delegate);
@@ -61,6 +62,8 @@ protected:
void itemMoved(int index, QQuickItem *item) override;
void itemRemoved(int index, QQuickItem *item) override;
+ void componentComplete() override;
+
QFont defaultFont() const override;
#if QT_CONFIG(accessibility)
diff --git a/src/quicktemplates/qquickmenubar_p_p.h b/src/quicktemplates/qquickmenubar_p_p.h
index f9a8acbd3d..98b234e1c8 100644
--- a/src/quicktemplates/qquickmenubar_p_p.h
+++ b/src/quicktemplates/qquickmenubar_p_p.h
@@ -19,6 +19,7 @@
#include <QtQuickTemplates2/private/qquickcontainer_p_p.h>
#include <QtCore/qpointer.h>
+#include <QtGui/qpa/qplatformmenu.h>
QT_BEGIN_NAMESPACE
@@ -38,19 +39,36 @@ public:
QQmlListProperty<QQuickMenu> menus();
QQmlListProperty<QObject> contentData();
- QQuickItem *beginCreateItem(QQuickMenu *menu);
- void completeCreateItem();
+ QQuickItem *createItemFromDelegate();
+ QQuickMenuBarItem *createMenuBarItem(QQuickMenu *menu);
- QQuickItem *createItem(QQuickMenu *menu);
+ void openCurrentMenu();
+ void closeCurrentMenu();
+ void activateMenuItem(int index);
- void toggleCurrentMenu(bool visible, bool activate);
void activateItem(QQuickMenuBarItem *item);
void activateNextItem();
void activatePreviousItem();
void onItemHovered();
void onItemTriggered();
- void onMenuAboutToHide();
+ void onMenuAboutToHide(QQuickMenu *menu);
+
+ void insertMenu(int index, QQuickMenu *menu, QQuickMenuBarItem *delegateItem);
+ QQuickMenu *takeMenu(int index);
+ void insertNativeMenu(QQuickMenu *menu);
+ void removeNativeMenu(QQuickMenu *menu);
+ void syncMenuBarItemVisibilty(QQuickMenuBarItem *menuBarItem);
+
+ QWindow *window() const;
+ int menuIndex(QQuickMenu *menu) const;
+
+ QPlatformMenuBar *nativeHandle() const;
+ bool useNativeMenuBar() const;
+ bool useNativeMenu(const QQuickMenu *menu) const;
+ void syncNativeMenuBarVisible();
+ void createNativeMenuBar();
+ void removeNativeMenuBar();
qreal getContentWidth() const override;
qreal getContentHeight() const override;
@@ -67,12 +85,15 @@ public:
QPalette defaultPalette() const override;
- bool popupMode = false;
- bool triggering = false;
+ bool closingCurrentMenu = false;
bool altPressed = false;
+ bool currentMenuOpen = false;
QQmlComponent *delegate = nullptr;
QPointer<QQuickMenuBarItem> currentItem;
QPointer<QQuickItem> windowContentItem;
+
+private:
+ std::unique_ptr<QPlatformMenuBar> handle;
};
QT_END_NAMESPACE
diff --git a/src/quicktemplates/qquickmenubaritem.cpp b/src/quicktemplates/qquickmenubaritem.cpp
index cc5fb83e40..68aff1e62d 100644
--- a/src/quicktemplates/qquickmenubaritem.cpp
+++ b/src/quicktemplates/qquickmenubaritem.cpp
@@ -92,6 +92,7 @@ QQuickMenuBarItem::QQuickMenuBarItem(QQuickItem *parent)
: QQuickAbstractButton(*(new QQuickMenuBarItemPrivate), parent)
{
setFocusPolicy(Qt::NoFocus);
+ d_func()->setSizePolicy(QLayoutPolicy::Fixed, QLayoutPolicy::Fixed);
}
/*!
diff --git a/src/quicktemplates/qquickmenuitem.cpp b/src/quicktemplates/qquickmenuitem.cpp
index c5b0ea2753..32a0719150 100644
--- a/src/quicktemplates/qquickmenuitem.cpp
+++ b/src/quicktemplates/qquickmenuitem.cpp
@@ -3,7 +3,7 @@
#include "qquickmenuitem_p.h"
#include "qquickmenuitem_p_p.h"
-#include "qquickmenu_p.h"
+#include "qquickmenu_p_p.h"
#include "qquickdeferredexecute_p_p.h"
#include <QtGui/qpa/qplatformtheme.h>
@@ -56,6 +56,44 @@ QT_BEGIN_NAMESPACE
\sa {Customizing Menu}, Menu, {Menu Controls}
*/
+/*!
+ \qmlproperty bool QtQuick.Controls::MenuItem::textPadding
+ \readonly
+ \since 6.8
+
+ This property holds the maximum \l implicitTextPadding found
+ among all the menu items inside the same \l menu.
+
+ This property can be used by the style to ensure that all MenuItems
+ inside the same Menu end up aligned with respect to the \l text.
+
+ A \l Menu can consist of meny different MenuItems, some can be checkable,
+ some can have an icon, and some will just contain text. And very often,
+ a style wants to make sure that the text inside all of them ends up
+ left-aligned (or right-aligned for \l mirrored items).
+ By letting each MenuItem assign its own minimum text padding to
+ \l implicitTextPadding (taking icons and checkmarks into account), but
+ using \l textPadding to actually position the \l text, all MenuItems should
+ end up being aligned
+
+ In order for this to work, all MenuItems should set \l implicitTextPadding
+ to be the minimum space needed from the left edge of the \l contentItem to
+ the text.
+
+ \sa implicitTextPadding
+*/
+
+/*!
+ \qmlproperty bool QtQuick.Controls::MenuItem::implicitTextPadding
+ \since 6.8
+
+ This property holds the minimum space needed from the left edge of the
+ \l contentItem to the text. It's used to calculate a common \l textPadding
+ among all the MenuItems inside a \l Menu.
+
+ \sa textPadding
+*/
+
void QQuickMenuItemPrivate::setMenu(QQuickMenu *newMenu)
{
Q_Q(QQuickMenuItem);
@@ -240,6 +278,26 @@ QFont QQuickMenuItem::defaultFont() const
return QQuickTheme::font(QQuickTheme::Menu);
}
+qreal QQuickMenuItem::implicitTextPadding() const
+{
+ return d_func()->implicitTextPadding;
+}
+
+void QQuickMenuItem::setImplicitTextPadding(qreal newImplicitTextPadding)
+{
+ Q_D(QQuickMenuItem);
+ if (qFuzzyCompare(d->implicitTextPadding, newImplicitTextPadding))
+ return;
+ d->implicitTextPadding = newImplicitTextPadding;
+ emit implicitTextPaddingChanged();
+}
+
+qreal QQuickMenuItem::textPadding() const
+{
+ Q_D(const QQuickMenuItem);
+ return d->menu ? QQuickMenuPrivate::get(d->menu)->textPadding : 0;
+}
+
#if QT_CONFIG(accessibility)
QAccessible::Role QQuickMenuItem::accessibleRole() const
{
@@ -247,6 +305,25 @@ QAccessible::Role QQuickMenuItem::accessibleRole() const
}
#endif
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QQuickMenuItem *menuItem)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ if (!menuItem) {
+ debug << "QQuickMenuItem(nullptr)";
+ return debug;
+ }
+
+ debug << menuItem->metaObject()->className() << '(' << static_cast<const void *>(menuItem);
+ if (!menuItem->objectName().isEmpty())
+ debug << ", name=" << menuItem->objectName();
+ debug << ", text=" << menuItem->text();
+ debug << ')';
+ return debug;
+}
+#endif // QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
#include "moc_qquickmenuitem_p.cpp"
diff --git a/src/quicktemplates/qquickmenuitem_p.h b/src/quicktemplates/qquickmenuitem_p.h
index fb99dc2502..786b6f8ae6 100644
--- a/src/quicktemplates/qquickmenuitem_p.h
+++ b/src/quicktemplates/qquickmenuitem_p.h
@@ -33,6 +33,8 @@ class Q_QUICKTEMPLATES2_EXPORT QQuickMenuItem : public QQuickAbstractButton
Q_PROPERTY(QQuickItem *arrow READ arrow WRITE setArrow NOTIFY arrowChanged FINAL REVISION(2, 3))
Q_PROPERTY(QQuickMenu *menu READ menu NOTIFY menuChanged FINAL REVISION(2, 3))
Q_PROPERTY(QQuickMenu *subMenu READ subMenu NOTIFY subMenuChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(qreal implicitTextPadding READ implicitTextPadding WRITE setImplicitTextPadding NOTIFY implicitTextPaddingChanged REVISION(6, 8))
+ Q_PROPERTY(qreal textPadding READ textPadding NOTIFY textPaddingChanged REVISION(6, 8))
Q_CLASSINFO("DeferredPropertyNames", "arrow,background,contentItem,indicator")
QML_NAMED_ELEMENT(MenuItem)
QML_ADDED_IN_VERSION(2, 0)
@@ -50,6 +52,10 @@ public:
QQuickMenu *menu() const;
QQuickMenu *subMenu() const;
+ qreal textPadding() const;
+ qreal implicitTextPadding() const;
+ void setImplicitTextPadding(qreal newImplicitTextPadding);
+
Q_SIGNALS:
void triggered();
void highlightedChanged();
@@ -57,6 +63,8 @@ Q_SIGNALS:
Q_REVISION(2, 3) void arrowChanged();
Q_REVISION(2, 3) void menuChanged();
Q_REVISION(2, 3) void subMenuChanged();
+ Q_REVISION(6, 8) void implicitTextPaddingChanged();
+ Q_REVISION(6, 8) void textPaddingChanged();
protected:
void componentComplete() override;
@@ -72,6 +80,10 @@ private:
Q_DECLARE_PRIVATE(QQuickMenuItem)
};
+#ifndef QT_NO_DEBUG_STREAM
+Q_QUICKTEMPLATES2_EXPORT QDebug operator<<(QDebug debug, const QQuickMenuItem *menuItem);
+#endif
+
QT_END_NAMESPACE
#endif // QQUICKMENUITEM_P_H
diff --git a/src/quicktemplates/qquickmenuitem_p_p.h b/src/quicktemplates/qquickmenuitem_p_p.h
index 63bcfa33f6..3ef4981570 100644
--- a/src/quicktemplates/qquickmenuitem_p_p.h
+++ b/src/quicktemplates/qquickmenuitem_p_p.h
@@ -48,6 +48,7 @@ public:
QQuickDeferredPointer<QQuickItem> arrow;
QQuickMenu *menu = nullptr;
QQuickMenu *subMenu = nullptr;
+ qreal implicitTextPadding;
};
QT_END_NAMESPACE
diff --git a/src/quicktemplates/qquicknativeicon.cpp b/src/quicktemplates/qquicknativeicon.cpp
new file mode 100644
index 0000000000..dfc8a4cc7e
--- /dev/null
+++ b/src/quicktemplates/qquicknativeicon.cpp
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquicknativeicon_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QUrl QQuickNativeIcon::source() const
+{
+ return m_source;
+}
+
+void QQuickNativeIcon::setSource(const QUrl& source)
+{
+ m_source = source;
+}
+
+QString QQuickNativeIcon::name() const
+{
+ return m_name;
+}
+
+void QQuickNativeIcon::setName(const QString& name)
+{
+ m_name = name;
+}
+
+bool QQuickNativeIcon::isMask() const
+{
+ return m_mask;
+}
+
+void QQuickNativeIcon::setMask(bool mask)
+{
+ m_mask = mask;
+}
+
+bool QQuickNativeIcon::operator==(const QQuickNativeIcon &other) const
+{
+ return m_source == other.m_source && m_name == other.m_name && m_mask == other.m_mask;
+}
+
+bool QQuickNativeIcon::operator!=(const QQuickNativeIcon &other) const
+{
+ return !(*this == other);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicknativeicon_p.cpp"
diff --git a/src/quicktemplates/qquicknativeicon_p.h b/src/quicktemplates/qquicknativeicon_p.h
new file mode 100644
index 0000000000..db0625954a
--- /dev/null
+++ b/src/quicktemplates/qquicknativeicon_p.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQUICKNATIVEICON_P_H
+#define QQUICKNATIVEICON_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qurl.h>
+#include <QtCore/qstring.h>
+
+#include <QtQml/qqmlengine.h>
+#include <QtCore/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+
+class QQuickNativeIcon
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ Q_PROPERTY(QUrl source READ source WRITE setSource FINAL)
+ Q_PROPERTY(QString name READ name WRITE setName FINAL)
+ Q_PROPERTY(bool mask READ isMask WRITE setMask FINAL)
+
+public:
+ QUrl source() const;
+ void setSource(const QUrl &source);
+
+ QString name() const;
+ void setName(const QString &name);
+
+ bool isMask() const;
+ void setMask(bool mask);
+
+ bool operator==(const QQuickNativeIcon &other) const;
+ bool operator!=(const QQuickNativeIcon &other) const;
+
+private:
+ bool m_mask = false;
+ QUrl m_source;
+ QString m_name;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKNATIVEICON_P_H
diff --git a/src/quicktemplates/qquicknativeiconloader.cpp b/src/quicktemplates/qquicknativeiconloader.cpp
new file mode 100644
index 0000000000..8b5dd54257
--- /dev/null
+++ b/src/quicktemplates/qquicknativeiconloader.cpp
@@ -0,0 +1,66 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquicknativeiconloader_p.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qmetaobject.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickNativeIconLoader::QQuickNativeIconLoader(int slot, QObject *parent)
+ : m_parent(parent),
+ m_slot(slot),
+ m_enabled(false)
+{
+ Q_ASSERT(slot != -1 && parent);
+}
+
+bool QQuickNativeIconLoader::isEnabled() const
+{
+ return m_enabled;
+}
+
+void QQuickNativeIconLoader::setEnabled(bool enabled)
+{
+ m_enabled = enabled;
+ if (m_enabled)
+ loadIcon();
+}
+
+QIcon QQuickNativeIconLoader::toQIcon() const
+{
+ const QIcon fallback = QPixmap::fromImage(image());
+ return QIcon::fromTheme(m_icon.name(), fallback);
+}
+
+QQuickIcon QQuickNativeIconLoader::icon() const
+{
+ return m_icon;
+}
+
+void QQuickNativeIconLoader::setIcon(const QQuickIcon &icon)
+{
+ m_icon = icon;
+ if (m_enabled)
+ loadIcon();
+}
+
+void QQuickNativeIconLoader::loadIcon()
+{
+ if (m_icon.source().isEmpty()) {
+ clear(m_parent);
+ } else {
+ load(qmlEngine(m_parent), m_icon.source());
+ if (m_slot != -1 && isLoading()) {
+ connectFinished(m_parent, m_slot);
+ m_slot = -1;
+ }
+ }
+
+ if (!isLoading())
+ m_parent->metaObject()->method(m_slot).invoke(m_parent);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates/qquicknativeiconloader_p.h b/src/quicktemplates/qquicknativeiconloader_p.h
new file mode 100644
index 0000000000..063178dc47
--- /dev/null
+++ b/src/quicktemplates/qquicknativeiconloader_p.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQUICKNATIVEICONLOADER_P_H
+#define QQUICKNATIVEICONLOADER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qurl.h>
+#include <QtCore/qstring.h>
+#include <QtGui/qicon.h>
+#include <QtQuick/private/qquickpixmap_p.h>
+#include <QtQuickTemplates2/private/qquickicon_p.h>
+
+#include "qquicknativeicon_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+
+class QQuickNativeIconLoader : public QQuickPixmap
+{
+public:
+ QQuickNativeIconLoader(int slot, QObject *parent);
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ QIcon toQIcon() const;
+
+ QQuickIcon icon() const;
+ void setIcon(const QQuickIcon &icon);
+
+private:
+ void loadIcon();
+
+ QObject *m_parent;
+ int m_slot;
+ bool m_enabled;
+ QQuickIcon m_icon;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKNATIVEICONLOADER_P_H
diff --git a/src/quicktemplates/qquicknativemenuitem.cpp b/src/quicktemplates/qquicknativemenuitem.cpp
new file mode 100644
index 0000000000..727fb87aa8
--- /dev/null
+++ b/src/quicktemplates/qquicknativemenuitem.cpp
@@ -0,0 +1,329 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquickmenuitem_p.h"
+
+#include <QtCore/qloggingcategory.h>
+//#include <QtGui/qicon.h>
+//#if QT_CONFIG(shortcut)
+//#include <QtGui/qkeysequence.h>
+//#endif
+#include <QtGui/qpa/qplatformmenu.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qguiapplication_p.h>
+//#include <QtQuickTemplates2/private/qquickshortcutcontext_p_p.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p_p.h>
+#include <QtQuickTemplates2/private/qquickaction_p.h>
+#include <QtQuickTemplates2/private/qquickmenu_p_p.h>
+#include <QtQuickTemplates2/private/qquickmenuseparator_p.h>
+#include <QtQuickTemplates2/private/qquicknativeiconloader_p.h>
+#include <QtQuickTemplates2/private/qquicknativemenuitem_p.h>
+#include <QtQuickTemplates2/private/qquickshortcutcontext_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcNativeMenuItem, "qt.quick.controls.nativemenuitem")
+
+/*!
+ \class QQuickNativeMenuItem
+ \brief A native menu item.
+ \since 6.7
+ \internal
+
+ Creates a native menu item from an Action/MenuItem/Menu,
+ and syncs the properties and signals. It can also represent a
+ MenuSeparator.
+
+ \sa Menu, Action
+*/
+
+QQuickNativeMenuItem *QQuickNativeMenuItem::createFromNonNativeItem(
+ QQuickMenu *parentMenu, QQuickItem *nonNativeItem)
+{
+ auto *menuItem = qobject_cast<QQuickMenuItem *>(nonNativeItem);
+ Type type = Type::Unknown;
+ if (menuItem) {
+ if (menuItem->action()) {
+ type = Type::Action;
+ } else if (menuItem->subMenu()) {
+ type = Type::SubMenu;
+ } else {
+ // It's a plain MenuItem, rather than a MenuItem created by us for an Action or Menu.
+ type = Type::MenuItem;
+ }
+ } else if (qobject_cast<QQuickMenuSeparator *>(nonNativeItem)) {
+ type = Type::Separator;
+ }
+
+ std::unique_ptr<QQuickNativeMenuItem> nativeMenuItemPtr(new QQuickNativeMenuItem(
+ parentMenu, nonNativeItem, type));
+ if (type == Type::Unknown) {
+ // It's not a Menu/Action/MenuSeparator that we're dealing with, but we still need
+ // to create the QQuickNativeMenu item for it so that our container has the same
+ // indices as the menu's contentModel.
+ return nativeMenuItemPtr.release();
+ }
+
+ qCDebug(lcNativeMenuItem) << "attemping to create native menu item for"
+ << nativeMenuItemPtr->debugText();
+ auto *parentMenuPrivate = QQuickMenuPrivate::get(parentMenu);
+ nativeMenuItemPtr->m_handle.reset(parentMenuPrivate->handle->createMenuItem());
+ if (!nativeMenuItemPtr->m_handle)
+ nativeMenuItemPtr->m_handle.reset(QGuiApplicationPrivate::platformTheme()->createPlatformMenuItem());
+ if (!nativeMenuItemPtr->m_handle)
+ return nullptr;
+
+ auto *nativeMenuItem = nativeMenuItemPtr.release();
+ switch (type) {
+ case Type::Action:
+ // Ensure that the action is triggered when the user clicks on a native menu item.
+ connect(nativeMenuItem->m_handle.get(), &QPlatformMenuItem::activated,
+ nativeMenuItem->action(), [nativeMenuItem, parentMenu](){
+ nativeMenuItem->action()->trigger(parentMenu);
+ });
+ // Handle programmatic changes in the Action.
+ connect(nativeMenuItem->action(), &QQuickAction::textChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(nativeMenuItem->action(), &QQuickAction::iconChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(nativeMenuItem->action(), &QQuickAction::enabledChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(nativeMenuItem->action(), &QQuickAction::checkedChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(nativeMenuItem->action(), &QQuickAction::checkableChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ break;
+ case Type::SubMenu:
+ nativeMenuItem->m_handle->setMenu(QQuickMenuPrivate::get(
+ nativeMenuItem->subMenu())->handle.get());
+
+ // Handle programmatic changes in the Menu.
+ connect(nativeMenuItem->subMenu(), &QQuickMenu::enabledChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(nativeMenuItem->subMenu(), &QQuickMenu::titleChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ break;
+ case Type::MenuItem:
+ // Ensure that the MenuItem is clicked when the user clicks on a native menu item.
+ connect(nativeMenuItem->m_handle.get(), &QPlatformMenuItem::activated,
+ menuItem, [menuItem](){
+ // This changes the checked state, which we need when syncing but also to ensure that
+ // the user can still use MenuItem's API even though they can't actually interact with it.
+ menuItem->toggle();
+ // The same applies here: allow users to respond to the MenuItem's clicked signal.
+ QQuickAbstractButtonPrivate::get(menuItem)->click();
+ });
+ // Handle programmatic changes in the MenuItem.
+ connect(menuItem, &QQuickMenuItem::textChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(menuItem, &QQuickMenuItem::iconChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(menuItem, &QQuickMenuItem::enabledChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(menuItem, &QQuickMenuItem::checkedChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(menuItem, &QQuickMenuItem::checkableChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ break;
+ case Type::Separator:
+ case Type::Unknown:
+ break;
+ }
+
+ return nativeMenuItem;
+}
+
+QQuickNativeMenuItem::QQuickNativeMenuItem(QQuickMenu *parentMenu, QQuickItem *nonNativeItem,
+ QQuickNativeMenuItem::Type type)
+ : QObject(parentMenu)
+ , m_parentMenu(parentMenu)
+ , m_nonNativeItem(nonNativeItem)
+ , m_type(type)
+{
+}
+
+QQuickNativeMenuItem::~QQuickNativeMenuItem()
+{
+ qCDebug(lcNativeMenuItem) << "destroying" << this << debugText();
+}
+
+QQuickAction *QQuickNativeMenuItem::action() const
+{
+ return m_type == Type::Action ? qobject_cast<QQuickMenuItem *>(m_nonNativeItem)->action() : nullptr;
+}
+
+QQuickMenu *QQuickNativeMenuItem::subMenu() const
+{
+ return m_type == Type::SubMenu ? qobject_cast<QQuickMenuItem *>(m_nonNativeItem)->subMenu() : nullptr;
+}
+
+QQuickMenuSeparator *QQuickNativeMenuItem::separator() const
+{
+ return m_type == Type::Separator ? qobject_cast<QQuickMenuSeparator *>(m_nonNativeItem) : nullptr;
+}
+
+QPlatformMenuItem *QQuickNativeMenuItem::handle() const
+{
+ return m_handle.get();
+}
+
+void QQuickNativeMenuItem::sync()
+{
+ if (m_type == Type::Unknown)
+ return;
+
+ if (m_syncing)
+ return;
+
+ QScopedValueRollback recursionGuard(m_syncing, true);
+
+ const auto *action = this->action();
+ const auto *separator = this->separator();
+ auto *subMenu = this->subMenu();
+ auto *menuItem = qobject_cast<QQuickMenuItem *>(m_nonNativeItem);
+
+ // Store the values in variables so that we can use it in the debug output below.
+ const bool enabled = action ? action->isEnabled()
+ : subMenu ? subMenu->isEnabled()
+ : menuItem && menuItem->isEnabled();
+ m_handle->setEnabled(enabled);
+// m_handle->setVisible(isVisible());
+
+ const bool isSeparator = separator != nullptr;
+ m_handle->setIsSeparator(isSeparator);
+
+ const bool checkable = action ? action->isCheckable() : menuItem && menuItem->isCheckable();
+ m_handle->setCheckable(checkable);
+
+ const bool checked = action ? action->isChecked() : menuItem && menuItem->isChecked();
+ m_handle->setChecked(checked);
+
+ m_handle->setRole(QPlatformMenuItem::TextHeuristicRole);
+
+ const QString text = action ? action->text()
+ : subMenu ? subMenu->title()
+ : menuItem ? menuItem->text() : QString();
+ m_handle->setText(text);
+
+// m_handle->setFont(m_font);
+// m_handle->setHasExclusiveGroup(m_group && m_group->isExclusive());
+ m_handle->setHasExclusiveGroup(false);
+
+ const QQuickIcon icon = effectiveIcon();
+ const auto *menuPrivate = QQuickMenuPrivate::get(m_parentMenu);
+ const auto *window = qGuiApp->topLevelWindows().first();
+ // We should reload the icon if the window's DPR has changed, regardless if its properties have changed.
+ // We can't check for ItemDevicePixelRatioHasChanged in QQuickMenu::itemChange,
+ // because that isn't sent when the menu isn't visible, and will never
+ // be sent for native menus. We instead store lastDevicePixelRatio in QQuickMenu
+ // (to avoid storing it for each menu item) and set it whenever it's opened.
+ const bool dprChanged = !qFuzzyCompare(window->devicePixelRatio(), menuPrivate->lastDevicePixelRatio);
+ if (!icon.isEmpty() && (icon != iconLoader()->icon() || dprChanged)) {
+ // This will load the icon, which will call sync() recursively, hence the m_syncing check.
+ reloadIcon();
+ }
+
+ if (subMenu) {
+ // Sync first as dynamically created menus may need to get the handle recreated.
+ auto *subMenuPrivate = QQuickMenuPrivate::get(subMenu);
+ subMenuPrivate->syncWithNativeMenu();
+ if (subMenuPrivate->handle)
+ m_handle->setMenu(subMenuPrivate->handle.get());
+ }
+
+#if QT_CONFIG(shortcut)
+ if (action)
+ m_handle->setShortcut(action->shortcut());
+#endif
+
+ if (m_parentMenu) {
+ auto *menuPrivate = QQuickMenuPrivate::get(m_parentMenu);
+ if (menuPrivate->handle)
+ menuPrivate->handle->syncMenuItem(m_handle.get());
+ }
+
+ qCDebug(lcNativeMenuItem) << "sync called on" << debugText() << "handle" << m_handle.get()
+ << "enabled:" << enabled << "isSeparator" << isSeparator << "checkable" << checkable
+ << "checked" << checked << "text" << text;
+}
+
+QQuickIcon QQuickNativeMenuItem::effectiveIcon() const
+{
+ if (const auto *action = this->action())
+ return action->icon();
+ if (const auto *subMenu = this->subMenu())
+ return subMenu->icon();
+ if (const auto *menuItem = qobject_cast<QQuickMenuItem *>(m_nonNativeItem))
+ return menuItem->icon();
+ return {};
+}
+
+QQuickNativeIconLoader *QQuickNativeMenuItem::iconLoader() const
+{
+ if (!m_iconLoader) {
+ QQuickNativeMenuItem *that = const_cast<QQuickNativeMenuItem *>(this);
+ static int slot = staticMetaObject.indexOfSlot("updateIcon()");
+ m_iconLoader = new QQuickNativeIconLoader(slot, that);
+ // Qt Labs Platform's QQuickMenuItem would call m_iconLoader->setEnabled(m_complete) here,
+ // but since QQuickMenuPrivate::maybeCreateAndInsertNativeItem asserts that the menu's
+ // completed loading, we can just set it to true.
+ m_iconLoader->setEnabled(true);
+ }
+ return m_iconLoader;
+}
+
+void QQuickNativeMenuItem::reloadIcon()
+{
+ iconLoader()->setIcon(effectiveIcon());
+ m_handle->setIcon(iconLoader()->toQIcon());
+}
+
+void QQuickNativeMenuItem::updateIcon()
+{
+ sync();
+}
+
+void QQuickNativeMenuItem::addShortcut()
+{
+#if QT_CONFIG(shortcut)
+ const auto *action = this->action();
+ const QKeySequence sequence = action ? action->shortcut() : QKeySequence();
+ if (!sequence.isEmpty() && action->isEnabled()) {
+ m_shortcutId = QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(this, sequence,
+ Qt::WindowShortcut, QQuickShortcutContext::matcher);
+ } else {
+ m_shortcutId = -1;
+ }
+#endif
+}
+
+void QQuickNativeMenuItem::removeShortcut()
+{
+#if QT_CONFIG(shortcut)
+ if (m_shortcutId == -1)
+ return;
+
+ QKeySequence sequence;
+ switch (m_type) {
+ case Type::Action:
+ sequence = action()->shortcut();
+ break;
+ default:
+ // TODO
+ break;
+ }
+
+ QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(m_shortcutId, this, sequence);
+#endif
+}
+
+QString QQuickNativeMenuItem::debugText() const
+{
+ switch (m_type) {
+ case Type::Action:
+ return QString::fromLatin1("Action(text = %1)").arg(action()->text());
+ case Type::SubMenu:
+ return QString::fromLatin1("Sub-menu(title = %1)").arg(subMenu()->title());
+ case Type::MenuItem:
+ return QString::fromLatin1("MenuItem(text = %1)").arg(
+ qobject_cast<QQuickMenuItem *>(m_nonNativeItem)->text());
+ case Type::Separator:
+ return QStringLiteral("Separator");
+ case Type::Unknown:
+ return QStringLiteral("(Unknown)");
+ }
+
+ Q_UNREACHABLE();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicknativemenuitem_p.cpp"
diff --git a/src/quicktemplates/qquicknativemenuitem_p.h b/src/quicktemplates/qquicknativemenuitem_p.h
new file mode 100644
index 0000000000..421d84df29
--- /dev/null
+++ b/src/quicktemplates/qquicknativemenuitem_p.h
@@ -0,0 +1,81 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQUICKNATIVEMENUITEM_P_H
+#define QQUICKNATIVEMENUITEM_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qobject.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+#include <QtQuickTemplates2/private/qquickicon_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAction;
+class QQuickNativeIconLoader;
+class QQuickMenu;
+class QQuickMenuSeparator;
+class QPlatformMenuItem;
+
+class Q_QUICKTEMPLATES2_EXPORT QQuickNativeMenuItem : public QObject
+{
+ Q_OBJECT
+
+public:
+ static QQuickNativeMenuItem *createFromNonNativeItem(
+ QQuickMenu *parentMenu, QQuickItem *nonNativeItem);
+ ~QQuickNativeMenuItem();
+
+ QQuickAction *action() const;
+ QQuickMenu *subMenu() const;
+ QQuickMenuSeparator *separator() const;
+ QPlatformMenuItem *handle() const;
+ void sync();
+
+ QQuickIcon effectiveIcon() const;
+ QQuickNativeIconLoader *iconLoader() const;
+ void reloadIcon();
+
+ QString debugText() const;
+
+private Q_SLOTS:
+ void updateIcon();
+
+private:
+ enum class Type {
+ Unknown,
+ // It's an Action or a MenuItem with an Action.
+ Action,
+ // It's a MenuItem without an Action.
+ MenuItem,
+ Separator,
+ SubMenu
+ };
+
+ explicit QQuickNativeMenuItem(QQuickMenu *parentMenu, QQuickItem *nonNativeItem, Type type);
+
+ void addShortcut();
+ void removeShortcut();
+
+ QQuickMenu *m_parentMenu = nullptr;
+ QQuickItem *m_nonNativeItem = nullptr;
+ Type m_type = Type::Unknown;
+ mutable QQuickNativeIconLoader *m_iconLoader = nullptr;
+ std::unique_ptr<QPlatformMenuItem> m_handle = nullptr;
+ int m_shortcutId = -1;
+ bool m_syncing = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKNATIVEMENUITEM_P_H
diff --git a/src/quicktemplates/qquickpage.cpp b/src/quicktemplates/qquickpage.cpp
index 55c6d3a178..9f19f5bae3 100644
--- a/src/quicktemplates/qquickpage.cpp
+++ b/src/quicktemplates/qquickpage.cpp
@@ -280,6 +280,11 @@ void QQuickPage::setTitle(const QString &title)
emit titleChanged();
}
+void QQuickPage::resetTitle()
+{
+ setTitle(QString());
+}
+
/*!
\qmlproperty Item QtQuick.Controls::Page::header
diff --git a/src/quicktemplates/qquickpage_p.h b/src/quicktemplates/qquickpage_p.h
index 02725cc7c5..7eaa443146 100644
--- a/src/quicktemplates/qquickpage_p.h
+++ b/src/quicktemplates/qquickpage_p.h
@@ -25,7 +25,7 @@ class QQuickPagePrivate;
class Q_QUICKTEMPLATES2_EXPORT QQuickPage : public QQuickPane
{
Q_OBJECT
- Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged FINAL)
+ Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged RESET resetTitle FINAL)
Q_PROPERTY(QQuickItem *header READ header WRITE setHeader NOTIFY headerChanged FINAL)
Q_PROPERTY(QQuickItem *footer READ footer WRITE setFooter NOTIFY footerChanged FINAL)
// 2.5 (Qt 5.12)
@@ -42,6 +42,7 @@ public:
QString title() const;
void setTitle(const QString &title);
+ void resetTitle();
QQuickItem *header() const;
void setHeader(QQuickItem *header);
diff --git a/src/quicktemplates/qquickpopup.cpp b/src/quicktemplates/qquickpopup.cpp
index 6aa88a465e..2b400b905d 100644
--- a/src/quicktemplates/qquickpopup.cpp
+++ b/src/quicktemplates/qquickpopup.cpp
@@ -5,6 +5,7 @@
#include "qquickpopup_p_p.h"
#include "qquickpopupanchors_p.h"
#include "qquickpopupitem_p_p.h"
+#include "qquickpopupwindow_p_p.h"
#include "qquickpopuppositioner_p_p.h"
#include "qquickapplicationwindow_p.h"
#include "qquickoverlay_p_p.h"
@@ -19,11 +20,13 @@
#include <QtQuick/private/qquickaccessibleattached_p.h>
#include <QtQuick/private/qquicktransition_p.h>
#include <QtQuick/private/qquickitem_p.h>
+#include <qpa/qplatformintegration.h>
+#include <private/qguiapplication_p.h>
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcDimmer, "qt.quick.controls.popup.dimmer")
-Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
+Q_LOGGING_CATEGORY(lcQuickPopup, "qt.quick.controls.popup")
/*!
\qmltype Popup
@@ -39,8 +42,8 @@ Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
used with \l Window or \l ApplicationWindow.
\qml
- import QtQuick.Window 2.2
- import QtQuick.Controls 2.12
+ import QtQuick.Window
+ import QtQuick.Controls
ApplicationWindow {
id: window
@@ -66,10 +69,6 @@ Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
}
\endqml
- In order to ensure that a popup is displayed above other items in the
- scene, it is recommended to use ApplicationWindow. ApplicationWindow also
- provides background dimming effects.
-
Popup does not provide a layout of its own, but requires you to position
its contents, for instance by creating a \l RowLayout or a \l ColumnLayout.
@@ -121,6 +120,29 @@ Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
}
\endcode
+ \section1 Popup Windows
+
+ Popup can behave in two different ways. Depending on the platform,
+ and what the value of the \l popupType property is.
+
+ Showing a popup as a separate top-level window is currently under tech-preview,
+ and therefore disabled by default. You can enable popup windows explicitly by
+ setting \l popupType to \c Popup.Window.
+
+ This will cause a separate popup window to be created,
+ which contains the \l contentItem and \l background items.
+
+ \section1 Popup Items
+
+ If the \l popupType property is set to \c Item,
+ or the platform doesn't support multiple windows,
+ the popup will instead create a item, which gets parented to the
+ \l{Overlay::overlay}{overlay} in the scene of the existing window.
+
+ In order to ensure that a popup is displayed above other items in the
+ scene, it is recommended to use ApplicationWindow. ApplicationWindow also
+ provides background dimming effects.
+
\section1 Popup Sizing
If only a single item is used within a Popup, it will resize to fit the
@@ -172,7 +194,7 @@ Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
}
\endcode
- \note The popup's \l{contentItem}{content item} gets parented to the
+ \note When using \l {Popup Items}, the popup's \l{contentItem}{content item} gets parented to the
\l{Overlay::overlay}{overlay}, and does not live within the popup's parent.
Because of that, a \l{Item::scale}{scale} applied to the tree in which
the popup lives does not apply to the visual popup. To make the popup
@@ -221,7 +243,8 @@ Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
\section1 Showing Non-Child Items in Front of Popup
- Popup sets its contentItem's
+
+ In cases where \l {Popup Windows} are not being used, Popup sets its contentItem's
\l{qtquick-visualcanvas-visualparent.html}{visual parent}
to be the window's \l{Overlay::overlay}{overlay}, in order to ensure that
the popup appears in front of everything else in the scene.
@@ -372,6 +395,18 @@ Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
\sa closed()
*/
+QQuickItem *QQuickPopup::findParentItem() const
+{
+ QObject *obj = parent();
+ while (obj) {
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj);
+ if (item)
+ return item;
+ obj = obj->parent();
+ }
+ return nullptr;
+}
+
const QQuickPopup::ClosePolicy QQuickPopupPrivate::DefaultClosePolicy = QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutside;
QQuickPopupPrivate::QQuickPopupPrivate()
@@ -384,7 +419,6 @@ void QQuickPopupPrivate::init()
Q_Q(QQuickPopup);
popupItem = new QQuickPopupItem(q);
popupItem->setVisible(false);
- q->setParentItem(qobject_cast<QQuickItem *>(parent));
QObject::connect(popupItem, &QQuickControl::paddingChanged, q, &QQuickPopup::paddingChanged);
QObject::connect(popupItem, &QQuickControl::backgroundChanged, q, &QQuickPopup::backgroundChanged);
QObject::connect(popupItem, &QQuickControl::contentItemChanged, q, &QQuickPopup::contentItemChanged);
@@ -468,7 +502,16 @@ bool QQuickPopupPrivate::handlePress(QQuickItem *item, const QPointF &point, ulo
Q_UNUSED(timestamp);
pressPoint = point;
outsidePressed = !contains(point);
- outsideParentPressed = outsidePressed && parentItem && !parentItem->contains(parentItem->mapFromScene(point));
+
+ if (outsidePressed && parentItem) {
+ // Note that the parentItem (e.g a menuBarItem, in case of a MenuBar) will
+ // live inside another window when using popup windows. We therefore need to
+ // map to and from global.
+ const QPointF globalPoint = item->mapToGlobal(point);
+ const QPointF localPoint = parentItem->mapFromGlobal(globalPoint);
+ outsideParentPressed = !parentItem->contains(localPoint);
+ }
+
tryClose(point, QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent);
return blockInput(item, point);
}
@@ -578,37 +621,17 @@ bool QQuickPopupPrivate::prepareEnterTransition()
return false;
if (transitionState != EnterTransition) {
- QQuickOverlay *overlay = QQuickOverlay::overlay(window);
- const auto popupStack = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups();
- popupItem->setParentItem(overlay);
- // if there is a stack of popups, and the current top popup item belongs to an
- // ancestor of this popup, then make sure that this popup's item is at the top
- // of the stack.
- const QQuickPopup *topPopup = popupStack.isEmpty() ? nullptr : popupStack.first();
- const QObject *ancestor = q;
- while (ancestor && topPopup) {
- if (ancestor == topPopup)
- break;
- ancestor = ancestor->parent();
- }
- if (topPopup && topPopup != q && ancestor) {
- QQuickItem *topPopupItem = popupStack.first()->popupItem();
- popupItem->stackAfter(topPopupItem);
- // If the popup doesn't have an explicit z value set, set it to be at least as
- // high as the current top popup item so that later opened popups are on top.
- if (!hasZ)
- popupItem->setZ(qMax(topPopupItem->z(), popupItem->z()));
- }
+ visible = true;
+ adjustPopupItemParentAndWindow();
if (dim)
createOverlay();
showDimmer();
emit q->aboutToShow();
- visible = true;
transitionState = EnterTransition;
- popupItem->setVisible(true);
getPositioner()->setParentItem(parentItem);
emit q->visibleChanged();
+ QQuickOverlay *overlay = QQuickOverlay::overlay(window);
auto *overlayPrivate = QQuickOverlayPrivate::get(overlay);
if (overlayPrivate->lastActiveFocusItem.isNull())
overlayPrivate->lastActiveFocusItem = window->activeFocusItem();
@@ -654,7 +677,7 @@ void QQuickPopupPrivate::finalizeEnterTransition()
{
Q_Q(QQuickPopup);
transitionState = NoTransition;
- getPositioner()->reposition();
+ reposition();
emit q->openedChanged();
opened();
}
@@ -663,7 +686,7 @@ void QQuickPopupPrivate::finalizeExitTransition()
{
Q_Q(QQuickPopup);
getPositioner()->setParentItem(nullptr);
- if (popupItem) {
+ if (popupItem && !popupWindow) {
popupItem->setParentItem(nullptr);
popupItem->setVisible(false);
}
@@ -698,8 +721,8 @@ void QQuickPopupPrivate::finalizeExitTransition()
overlayPrivate->lastActiveFocusItem = nullptr;
}
}
-
visible = false;
+ adjustPopupItemParentAndWindow();
transitionState = NoTransition;
hadActiveFocusBeforeExitTransition = false;
emit q->visibleChanged();
@@ -716,6 +739,11 @@ void QQuickPopupPrivate::opened()
emit q->opened();
}
+Qt::WindowFlags QQuickPopupPrivate::popupWindowType() const
+{
+ return Qt::Popup | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint;
+}
+
QMarginsF QQuickPopupPrivate::getMargins() const
{
Q_Q(const QQuickPopup);
@@ -871,6 +899,67 @@ QPalette QQuickPopupPrivate::defaultPalette() const
return QQuickTheme::palette(QQuickTheme::System);
}
+bool QQuickPopupPrivate::usePopupWindow() const
+{
+ return QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::Capability::MultipleWindows)
+ && m_popupType == QQuickPopup::PopupType::Window
+ && popupWindowType() != Qt::Widget; // We use Qt::Widget here, to allow some popup derived types, like drawer, to opt out of using separate windows.
+}
+
+void QQuickPopupPrivate::adjustPopupItemParentAndWindow()
+{
+ Q_Q(QQuickPopup);
+ QQuickOverlay *overlay = QQuickOverlay::overlay(window);
+
+ if (visible && popupWindowDirty) {
+ popupItem->setParentItem(overlay);
+ if (popupWindow) {
+ popupWindow->deleteLater();
+ popupWindow = nullptr;
+ }
+ popupWindowDirty = false;
+ }
+
+ if (usePopupWindow()) {
+ if (!popupWindow) {
+ popupWindow = new QQuickPopupWindow(q, window);
+ popupWindow->setModality(modal ? Qt::ApplicationModal : Qt::NonModal);
+ popupItem->resetTitle();
+ popupWindow->setTitle(m_title);
+ popupItem->setParentItem(popupWindow->contentItem());
+ popupItem->forceActiveFocus(Qt::PopupFocusReason);
+ }
+ popupItem->setVisible(true);
+ popupWindow->setVisible(visible);
+ } else {
+ if (visible) {
+ popupItem->setParentItem(overlay);
+ const auto popupStack = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups();
+ // if there is a stack of popups, and the current top popup item belongs to an
+ // ancestor of this popup, then make sure that this popup's item is at the top
+ // of the stack.
+ const QQuickPopup *topPopup = popupStack.isEmpty() ? nullptr : popupStack.first();
+ const QObject *ancestor = q;
+ while (ancestor && topPopup) {
+ if (ancestor == topPopup)
+ break;
+ ancestor = ancestor->parent();
+ }
+ if (topPopup && topPopup != q && ancestor) {
+ QQuickItem *topPopupItem = popupStack.first()->popupItem();
+ popupItem->stackAfter(topPopupItem);
+ // If the popup doesn't have an explicit z value set, set it to be at least as
+ // high as the current top popup item so that later opened popups are on top.
+ if (!hasZ)
+ popupItem->setZ(qMax(topPopupItem->z(), popupItem->z()));
+ }
+ }
+
+ popupItem->setTitle(m_title);
+ popupItem->setVisible(visible);
+ }
+}
+
static QQuickItem *createDimmer(QQmlComponent *component, QQuickPopup *popup, QQuickItem *parent)
{
QQuickItem *item = nullptr;
@@ -1181,6 +1270,9 @@ void QQuickPopup::setPosition(const QPointF &pos)
of an already open popup, then it will be stacked on top of its parent.
This ensures that children are never hidden under their parents.
+ If the popup has its own window, the z-value will determine the window
+ stacking order instead.
+
The default z-value is \c 0.
\sa x, y
@@ -1195,9 +1287,13 @@ void QQuickPopup::setZ(qreal z)
{
Q_D(QQuickPopup);
d->hasZ = true;
- if (qFuzzyCompare(z, d->popupItem->z()))
+ bool previousZ = d->popupWindow ? d->popupWindow->z() : d->popupItem->z();
+ if (qFuzzyCompare(z, previousZ))
return;
- d->popupItem->setZ(z);
+ if (d->popupWindow)
+ d->popupWindow->setZ(z);
+ else
+ d->popupItem->setZ(z);
emit zChanged();
}
@@ -1223,7 +1319,16 @@ void QQuickPopup::setWidth(qreal width)
{
Q_D(QQuickPopup);
d->hasWidth = true;
- d->popupItem->setWidth(width);
+
+ // QQuickPopupWindow::setWidth() triggers a window resize event.
+ // This will cause QQuickPopupWindow::resizeEvent() to resize
+ // the popupItem. QQuickPopupItem::geometryChanged() calls QQuickPopup::geometryChange(),
+ // which emits widthChanged().
+
+ if (d->popupWindow)
+ d->popupWindow->setWidth(width);
+ else
+ d->popupItem->setWidth(width);
}
void QQuickPopup::resetWidth()
@@ -1253,7 +1358,16 @@ void QQuickPopup::setHeight(qreal height)
{
Q_D(QQuickPopup);
d->hasHeight = true;
- d->popupItem->setHeight(height);
+
+ // QQuickPopupWindow::setHeight() triggers a window resize event.
+ // This will cause QQuickPopupWindow::resizeEvent() to resize
+ // the popupItem. QQuickPopupItem::geometryChanged() calls QQuickPopup::geometryChange(),
+ // which emits heightChanged().
+
+ if (d->popupWindow)
+ d->popupWindow->setHeight(height);
+ else
+ d->popupItem->setHeight(height);
}
void QQuickPopup::resetHeight()
@@ -1862,7 +1976,7 @@ void QQuickPopup::resetParentItem()
if (QQuickWindow *window = qobject_cast<QQuickWindow *>(parent()))
setParentItem(window->contentItem());
else
- setParentItem(qobject_cast<QQuickItem *>(parent()));
+ setParentItem(findParentItem());
}
/*!
@@ -1993,17 +2107,18 @@ QQmlListProperty<QQuickItem> QQuickPopupPrivate::contentChildren()
\qmlproperty bool QtQuick.Controls::Popup::clip
This property holds whether clipping is enabled. The default value is \c false.
+ Clipping only works when the popup isn't in its own window.
*/
bool QQuickPopup::clip() const
{
Q_D(const QQuickPopup);
- return d->popupItem->clip();
+ return d->popupItem->clip() && !d->usePopupWindow();
}
void QQuickPopup::setClip(bool clip)
{
Q_D(QQuickPopup);
- if (clip == d->popupItem->clip())
+ if (clip == d->popupItem->clip() || d->usePopupWindow())
return;
d->popupItem->setClip(clip);
emit clipChanged();
@@ -2083,6 +2198,7 @@ void QQuickPopup::setModal(bool modal)
if (d->modal == modal)
return;
d->modal = modal;
+ d->popupWindowDirty = true;
if (d->complete && d->visible)
d->toggleOverlay();
emit modalChanged();
@@ -2613,6 +2729,47 @@ void QQuickPopup::resetBottomInset()
d->popupItem->resetBottomInset();
}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::Popup::popupType
+ \since 6.8
+ \preliminary
+
+ This property determines the type of popup that will be created.
+
+ Available options:
+ \value Default Let Qt decide the optimal popup type, depending on the system. This is the default value.
+ While \c Popup.Window is in tech-preview, \c Popup.Default will be equal to \c Popup.Item.
+ But this is likely to change in a future release.
+ \value Item The popup will be embedded into the \l{Popup Items}{same scene as the parent}, without the use of a separate window.
+ \value Window The popup will be presented in a \l {Popup Windows}{separate window}. If the platform doesn't support multiple windows,
+ \c Popup.Item will be used instead. This option is currently under tech-preview.
+ \value Native The popup will be native to the platform. If the platform doesn't support native popups,
+ \c Popup.Window will be used instead. This option is currently under tech-preview.
+ \sa {Popup Windows}, {Popup Items}
+*/
+QQuickPopup::PopupType QQuickPopup::popupType() const
+{
+ Q_D(const QQuickPopup);
+ return d->m_popupType;
+}
+
+void QQuickPopup::setPopupType(PopupType popupType)
+{
+ Q_D(QQuickPopup);
+ if (d->m_popupType == popupType)
+ return;
+
+ d->m_popupType = popupType;
+
+ emit popupTypeChanged();
+}
+
+void QQuickPopup::resetPopupType()
+{
+ setPopupType(PopupType::Default);
+}
+
/*!
\since QtQuick.Controls 2.3 (Qt 5.10)
\qmlproperty palette QtQuick.Controls::Popup::palette
@@ -2683,7 +2840,7 @@ void QQuickPopup::classBegin()
void QQuickPopup::componentComplete()
{
Q_D(QQuickPopup);
- qCDebug(lcPopup) << "componentComplete" << this;
+ qCDebug(lcQuickPopup) << "componentComplete" << this;
if (!parentItem())
resetParentItem();
@@ -2843,7 +3000,7 @@ void QQuickPopup::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
void QQuickPopup::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
{
- qCDebug(lcPopup) << "contentSizeChange called on" << this << "with newSize" << newSize << "oldSize" << oldSize;
+ qCDebug(lcQuickPopup) << "contentSizeChange called on" << this << "with newSize" << newSize << "oldSize" << oldSize;
if (!qFuzzyCompare(newSize.width(), oldSize.width()))
emit contentWidthChanged();
if (!qFuzzyCompare(newSize.height(), oldSize.height()))
@@ -2860,7 +3017,7 @@ void QQuickPopup::fontChange(const QFont &newFont, const QFont &oldFont)
void QQuickPopup::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
{
Q_D(QQuickPopup);
- qCDebug(lcPopup) << "geometryChange called on" << this << "with newGeometry" << newGeometry << "oldGeometry" << oldGeometry;
+ qCDebug(lcQuickPopup) << "geometryChange called on" << this << "with newGeometry" << newGeometry << "oldGeometry" << oldGeometry;
d->reposition();
if (!qFuzzyCompare(newGeometry.width(), oldGeometry.width())) {
emit widthChanged();
diff --git a/src/quicktemplates/qquickpopup_p.h b/src/quicktemplates/qquickpopup_p.h
index 9ffd94e70a..1ca4a18621 100644
--- a/src/quicktemplates/qquickpopup_p.h
+++ b/src/quicktemplates/qquickpopup_p.h
@@ -101,6 +101,7 @@ class Q_QUICKTEMPLATES2_EXPORT QQuickPopup : public QObject, public QQmlParserSt
Q_PROPERTY(qreal leftInset READ leftInset WRITE setLeftInset RESET resetLeftInset NOTIFY leftInsetChanged FINAL REVISION(2, 5))
Q_PROPERTY(qreal rightInset READ rightInset WRITE setRightInset RESET resetRightInset NOTIFY rightInsetChanged FINAL REVISION(2, 5))
Q_PROPERTY(qreal bottomInset READ bottomInset WRITE setBottomInset RESET resetBottomInset NOTIFY bottomInsetChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(PopupType popupType READ popupType WRITE setPopupType RESET resetPopupType NOTIFY popupTypeChanged FINAL REVISION(6, 8))
Q_CLASSINFO("DeferredPropertyNames", "background,contentItem")
Q_CLASSINFO("DefaultProperty", "contentData")
QML_NAMED_ELEMENT(Popup)
@@ -222,11 +223,11 @@ public:
void setDim(bool dim);
void resetDim();
- bool isVisible() const;
+ virtual bool isVisible() const;
virtual void setVisible(bool visible);
qreal opacity() const;
- void setOpacity(qreal opacity);
+ virtual void setOpacity(qreal opacity);
qreal scale() const;
void setScale(qreal scale);
@@ -311,6 +312,18 @@ public:
void setBottomInset(qreal inset);
void resetBottomInset();
+ enum PopupType {
+ Default,
+ Item,
+ Window,
+ Native
+ };
+ Q_ENUM(PopupType)
+
+ PopupType popupType() const;
+ void setPopupType(PopupType);
+ void resetPopupType();
+
public Q_SLOTS:
void open();
void close();
@@ -378,6 +391,7 @@ Q_SIGNALS:
Q_REVISION(2, 5) void leftInsetChanged();
Q_REVISION(2, 5) void rightInsetChanged();
Q_REVISION(2, 5) void bottomInsetChanged();
+ Q_REVISION(6, 8) void popupTypeChanged();
protected:
QQuickPopup(QQuickPopupPrivate &dd, QObject *parent);
@@ -433,8 +447,11 @@ protected:
bool setAccessibleProperty(const char *propertyName, const QVariant &value);
private:
+ QQuickItem *findParentItem() const;
+
Q_DISABLE_COPY(QQuickPopup)
Q_DECLARE_PRIVATE(QQuickPopup)
+ friend class QQuickPopupWindow;
friend class QQuickPopupItem;
friend class QQuickOverlay;
friend class QQuickOverlayPrivate;
diff --git a/src/quicktemplates/qquickpopup_p_p.h b/src/quicktemplates/qquickpopup_p_p.h
index 5572dd87d1..ff364489fb 100644
--- a/src/quicktemplates/qquickpopup_p_p.h
+++ b/src/quicktemplates/qquickpopup_p_p.h
@@ -34,6 +34,7 @@ class QQuickTransitionManager;
class QQuickPopup;
class QQuickPopupAnchors;
class QQuickPopupItem;
+class QQuickPopupWindow;
class QQuickPopupPrivate;
class QQuickPopupPositioner;
@@ -84,6 +85,7 @@ public:
virtual bool handlePress(QQuickItem* item, const QPointF &point, ulong timestamp);
virtual bool handleMove(QQuickItem* item, const QPointF &point, ulong timestamp);
virtual bool handleRelease(QQuickItem* item, const QPointF &point, ulong timestamp);
+ virtual bool handleReleaseWithoutGrab(const QEventPoint &) { return false; }
virtual void handleUngrab();
bool handleMouseEvent(QQuickItem *item, QMouseEvent *event);
@@ -94,6 +96,8 @@ public:
void reposition();
+ bool usePopupWindow() const;
+ void adjustPopupItemParentAndWindow();
void createOverlay();
void destroyDimmer();
void toggleOverlay();
@@ -109,6 +113,8 @@ public:
virtual void opened();
+ virtual Qt::WindowFlags popupWindowType() const;
+
QMarginsF getMargins() const;
void setTopMargin(qreal value, bool reset = false);
@@ -157,6 +163,7 @@ public:
bool outsideParentPressed = false;
bool inDestructor = false;
bool relaxEdgeConstraint = false;
+ bool popupWindowDirty = false;
int touchId = -1;
qreal x = 0;
qreal y = 0;
@@ -176,6 +183,7 @@ public:
QQuickTransition *enter = nullptr;
QQuickTransition *exit = nullptr;
QQuickPopupItem *popupItem = nullptr;
+ QQuickPopupWindow *popupWindow = nullptr;
QQuickPopupPositioner *positioner = nullptr;
QList<QQuickStateAction> enterActions;
QList<QQuickStateAction> exitActions;
@@ -184,6 +192,8 @@ public:
qreal explicitDimmerOpacity = 0;
qreal prevOpacity = 0;
qreal prevScale = 0;
+ QString m_title;
+ QQuickPopup::PopupType m_popupType = QQuickPopup::Default;
friend class QQuickPopupTransitionManager;
};
diff --git a/src/quicktemplates/qquickpopupitem.cpp b/src/quicktemplates/qquickpopupitem.cpp
index 574ea4589a..e60e4c5d77 100644
--- a/src/quicktemplates/qquickpopupitem.cpp
+++ b/src/quicktemplates/qquickpopupitem.cpp
@@ -146,6 +146,18 @@ QPalette QQuickPopupItemPrivate::parentPalette(const QPalette &fallbackPalette)
return QQuickPopupPrivate::get(popup)->parentPalette(fallbackPalette);
}
+bool QQuickPopupItem::contains(const QPointF &point) const
+{
+ Q_D(const QQuickPopupItem);
+ // A popup will often contain a drop shadow. And when determining if a point
+ // is inside the popup, we want to exclude that shadow from the test, and only
+ // consider the background rect.
+ const QRectF backgroundRect = boundingRect().adjusted(
+ d->popup->leftInset(), d->popup->topInset(),
+ -d->popup->rightInset(), -d->popup->bottomInset());
+ return backgroundRect.contains(point);
+}
+
void QQuickPopupItem::updatePolish()
{
Q_D(QQuickPopupItem);
diff --git a/src/quicktemplates/qquickpopupitem_p_p.h b/src/quicktemplates/qquickpopupitem_p_p.h
index c0ef0f4d85..cb0d2709cd 100644
--- a/src/quicktemplates/qquickpopupitem_p_p.h
+++ b/src/quicktemplates/qquickpopupitem_p_p.h
@@ -30,6 +30,8 @@ class Q_QUICKTEMPLATES2_EXPORT QQuickPopupItem : public QQuickPage
public:
explicit QQuickPopupItem(QQuickPopup *popup);
+ bool contains(const QPointF &point) const override;
+
protected:
void updatePolish() override;
diff --git a/src/quicktemplates/qquickpopuppositioner.cpp b/src/quicktemplates/qquickpopuppositioner.cpp
index f8113a5526..c211da0ff0 100644
--- a/src/quicktemplates/qquickpopuppositioner.cpp
+++ b/src/quicktemplates/qquickpopuppositioner.cpp
@@ -5,6 +5,7 @@
#include "qquickpopuppositioner_p_p.h"
#include "qquickpopupanchors_p.h"
#include "qquickpopupitem_p_p.h"
+#include "qquickpopupwindow_p_p.h"
#include "qquickpopup_p_p.h"
#include <QtCore/qloggingcategory.h>
@@ -72,7 +73,44 @@ void QQuickPopupPositioner::setParentItem(QQuickItem *parent)
void QQuickPopupPositioner::reposition()
{
- QQuickItem *popupItem = m_popup->popupItem();
+ auto p = QQuickPopupPrivate::get(popup());
+ QQuickPopupItem *popupItem = static_cast<QQuickPopupItem *>(m_popup->popupItem());
+
+ if (p->usePopupWindow()) {
+ // If the popup has insets, it means that it could have a drop shadow. At least
+ // that's the use case insets are documented to solve. And then we align the
+ // window so that the corner of the background, rather than the drop shadow,
+ // ends up at the requested position. We only do that for positive insets, since
+ // negative insets means that the background is already at the correct position.
+ // Note that this might move the popup out of the window again, but only the shadow.
+ QPoint pos(p->x, p->y);
+ if (popupItem->leftInset() > 0)
+ pos.rx() -= popupItem->leftInset();
+ if (popupItem->topInset() > 0)
+ pos.ry() -= popupItem->topInset();
+
+ if (!p->popupWindow || !p->parentItem) {
+ p->effectiveX = pos.x();
+ p->effectiveY = pos.y();
+ return;
+ }
+
+ const QQuickItem *centerInParent = p->anchors ? p->getAnchors()->centerIn() : nullptr;
+ const QQuickOverlay *centerInOverlay = qobject_cast<const QQuickOverlay *>(centerInParent);
+
+ if (centerInParent == p->parentItem || centerInOverlay) {
+ pos = centerInOverlay ? QPoint(qRound(centerInOverlay->width() / 2.0), qRound(centerInOverlay->height() / 2.0))
+ : QPoint(qRound(p->parentItem->width() / 2.0), qRound(p->parentItem->height() / 2.0));
+ pos -= QPoint(qRound(p->popupItem->width() / 2.0), qRound(p->popupItem->height() / 2.0));
+
+ } else if (centerInParent)
+ qmlWarning(popup()) << "Popup can only be centered within its immediate parent or Overlay.overlay";
+
+ const QPointF globalCoords = p->parentItem->mapToGlobal(pos.x(), pos.y());
+ p->popupWindow->setPosition(globalCoords.x(), globalCoords.y());
+ return;
+ }
+
if (!popupItem->isVisible())
return;
@@ -90,14 +128,12 @@ void QQuickPopupPositioner::reposition()
bool widthAdjusted = false;
bool heightAdjusted = false;
- QQuickPopupPrivate *p = QQuickPopupPrivate::get(m_popup);
const QQuickItem *centerInParent = p->anchors ? p->getAnchors()->centerIn() : nullptr;
const QQuickOverlay *centerInOverlay = qobject_cast<const QQuickOverlay*>(centerInParent);
QRectF rect(!centerInParent ? p->allowHorizontalMove ? p->x : popupItem->x() : 0,
!centerInParent ? p->allowVerticalMove ? p->y : popupItem->y() : 0,
- !p->hasWidth && iw > 0 ? iw : w,
- !p->hasHeight && ih > 0 ? ih : h);
+ !p->hasWidth && iw > 0 ? iw : w, !p->hasHeight && ih > 0 ? ih : h);
bool relaxEdgeConstraint = p->relaxEdgeConstraint;
if (m_parentItem) {
// m_parentItem is the parent that the popup should open in,
@@ -230,12 +266,21 @@ void QQuickPopupPositioner::reposition()
m_positioning = true;
+ // Ensure that the corner of the background item is placed at the
+ // designated location, even if this means that visual effects like
+ // drop shadows end up outside the window.
+ if (popupItem->leftInset() > 0)
+ rect.translate(-popupItem->leftInset(), 0);
+ if (popupItem->topInset() > 0)
+ rect.translate(0, -popupItem->topInset());
+
popupItem->setPosition(rect.topLeft());
// If the popup was assigned a parent, rect will be in scene coordinates,
// so we need to map its top left back to item coordinates.
// However, if centering within the overlay, the coordinates will be relative
// to the window, so we don't need to do anything.
+ // The same applies to popups that are in their own dedicated window.
const QPointF effectivePos = m_parentItem && !centerInOverlay ? m_parentItem->mapFromScene(rect.topLeft()) : rect.topLeft();
if (!qFuzzyCompare(p->effectiveX, effectivePos.x())) {
p->effectiveX = effectivePos.x();
diff --git a/src/quicktemplates/qquickpopupwindow.cpp b/src/quicktemplates/qquickpopupwindow.cpp
new file mode 100644
index 0000000000..55af909aa1
--- /dev/null
+++ b/src/quicktemplates/qquickpopupwindow.cpp
@@ -0,0 +1,277 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquickpopupwindow_p_p.h"
+#include "qquickcombobox_p.h"
+#include "qquickpopup_p.h"
+#include "qquickpopup_p_p.h"
+#include "qquickmenu_p_p.h"
+#include "qquickmenubar_p_p.h"
+#include "qquickpopupitem_p_p.h"
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/private/qeventpoint_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickwindowmodule_p.h>
+#include <QtQuick/private/qquickwindowmodule_p_p.h>
+#include <qpa/qplatformwindow_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcPopupWindow, "qt.quick.controls.popup.window")
+
+class QQuickPopupWindowPrivate : public QQuickWindowQmlImplPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickPopupWindow)
+
+public:
+ QPointer<QQuickItem> m_popupItem;
+ QPointer<QQuickPopup> m_popup;
+
+ void forwardEventToParentMenuOrMenuBar(QEvent *event);
+};
+
+QQuickPopupWindow::QQuickPopupWindow(QQuickPopup *popup, QWindow *parent)
+ : QQuickWindowQmlImpl(*(new QQuickPopupWindowPrivate), nullptr)
+{
+ Q_D(QQuickPopupWindow);
+
+ d->m_popup = popup;
+ d->m_popupItem = popup->popupItem();
+ setTransientParent(parent);
+
+ connect(d->m_popup, &QQuickPopup::windowChanged, this, &QQuickPopupWindow::windowChanged);
+ connect(d->m_popup, &QQuickPopup::implicitWidthChanged, this, &QQuickPopupWindow::implicitWidthChanged);
+ connect(d->m_popup, &QQuickPopup::implicitHeightChanged, this, &QQuickPopupWindow::implicitHeightChanged);
+ connect(d->m_popup->window(), &QWindow::xChanged, this, &QQuickPopupWindow::parentWindowXChanged);
+ connect(d->m_popup->window(), &QWindow::yChanged, this, &QQuickPopupWindow::parentWindowYChanged);
+
+ setWidth(d->m_popupItem->implicitWidth());
+ setHeight(d->m_popupItem->implicitHeight());
+
+ const auto flags = QQuickPopupPrivate::get(popup)->popupWindowType();
+
+ // For popup windows, we'll need to draw everything, in order to have enough control over the styling.
+ if (flags & Qt::Popup)
+ setColor(QColorConstants::Transparent);
+
+ setFlags(flags);
+
+ qCDebug(lcPopupWindow) << "Created popup window with flags: " << flags;
+}
+
+QQuickPopupWindow::~QQuickPopupWindow()
+{
+ Q_D(QQuickPopupWindow);
+ disconnect(d->m_popup, &QQuickPopup::windowChanged, this, &QQuickPopupWindow::windowChanged);
+ disconnect(d->m_popup, &QQuickPopup::implicitWidthChanged, this, &QQuickPopupWindow::implicitWidthChanged);
+ disconnect(d->m_popup, &QQuickPopup::implicitHeightChanged, this, &QQuickPopupWindow::implicitHeightChanged);
+ disconnect(d->m_popup->window(), &QWindow::xChanged, this, &QQuickPopupWindow::parentWindowXChanged);
+ disconnect(d->m_popup->window(), &QWindow::yChanged, this, &QQuickPopupWindow::parentWindowYChanged);
+}
+
+QQuickPopup *QQuickPopupWindow::popup() const
+{
+ Q_D(const QQuickPopupWindow);
+ return d->m_popup;
+}
+
+void QQuickPopupWindow::hideEvent(QHideEvent *e)
+{
+ Q_D(QQuickPopupWindow);
+ QQuickWindow::hideEvent(e);
+ if (QQuickPopup *popup = d->m_popup) {
+ QQuickPopupPrivate::get(popup)->visible = false;
+ emit popup->visibleChanged();
+ }
+}
+
+void QQuickPopupWindow::moveEvent(QMoveEvent *e)
+{
+ handlePopupPositionChangeFromWindowSystem(e->pos());
+}
+
+void QQuickPopupWindow::resizeEvent(QResizeEvent *e)
+{
+ Q_D(QQuickPopupWindow);
+ QQuickWindowQmlImpl::resizeEvent(e);
+
+ if (!d->m_popupItem)
+ return;
+
+ qCDebug(lcPopupWindow) << "A window system event changed the popup's size to be " << e->size();
+ d->m_popupItem->setWidth(e->size().width());
+ d->m_popupItem->setHeight(e->size().height());
+}
+
+/*! \internal
+ We want to handle menus specially, compared to other popups. For menus, we
+ want all open parent menus and sub menus that belong together to almost
+ act as a single popup WRT hover event delivery. This will allow the user to
+ hover and highlight MenuItems inside all of them, not just the leaf menu.
+ This function will therefore find the menu, or menu bar, under the event's
+ position, and forward the event to it. But note that this forwarding will
+ happen in parallel with normal event delivery (we don't eat the events), as
+ we don't want to break the delivery to e.g grabbers.
+ */
+void QQuickPopupWindowPrivate::forwardEventToParentMenuOrMenuBar(QEvent *event)
+{
+ Q_Q(QQuickPopupWindow);
+
+ if (!event->isPointerEvent())
+ return;
+ auto menu = qobject_cast<QQuickMenu *>(q->popup());
+ if (!menu)
+ return;
+
+ auto *pe = static_cast<QPointerEvent *>(event);
+ const QPointF globalPos = pe->points().first().globalPosition();
+
+ // If there is a Menu or a MenuBar under the mouse, resolve its window.
+ QQuickPopupWindow *targetPopupWindow = nullptr;
+ QQuickWindow *targetWindow = nullptr;
+
+ QObject *menuParent = menu;
+ while (menuParent) {
+ if (auto parentMenu = qobject_cast<QQuickMenu *>(menuParent)) {
+ QQuickPopupWindow *popupWindow = QQuickMenuPrivate::get(parentMenu)->popupWindow;
+ auto popup_d = QQuickPopupPrivate::get(popupWindow->popup());
+ QPointF scenePos = popupWindow->contentItem()->mapFromGlobal(globalPos);
+ if (popup_d->contains(scenePos)) {
+ targetPopupWindow = popupWindow;
+ targetWindow = popupWindow;
+ break;
+ }
+ } else if (auto menuBar = qobject_cast<QQuickMenuBar *>(menuParent)) {
+ const QPointF menuBarPos = menuBar->mapFromGlobal(globalPos);
+ if (menuBar->contains(menuBarPos))
+ targetWindow = menuBar->window();
+ break;
+ }
+
+ menuParent = menuParent->parent();
+ }
+
+ if (!targetPopupWindow) {
+ if (pe->isBeginEvent()) {
+ // A QQuickPopupWindow can be bigger than the Popup itself, to make room
+ // for a drop-shadow. Close all popups if the user clicks either on the
+ // shadow or outside the window.
+ QGuiApplicationPrivate::closeAllPopups();
+ return;
+ }
+ }
+
+ if (!targetWindow)
+ return;
+
+ if (pe->isUpdateEvent()){
+ // Forward move events to the target window
+ const auto scenePos = pe->point(0).scenePosition();
+ const auto translatedScenePos = targetWindow->mapFromGlobal(globalPos);
+ QMutableEventPoint::setScenePosition(pe->point(0), translatedScenePos);
+ auto *grabber = pe->exclusiveGrabber(pe->point(0));
+
+ if (grabber) {
+ // Temporarily disable the grabber, to stop the delivery agent inside
+ // targetWindow from forwarding the event to an item outside the menu
+ // or menubar. This is especially important to support a press on e.g
+ // a MenuBarItem, followed by a drag-and-release on top of a MenuItem.
+ pe->setExclusiveGrabber(pe->point(0), nullptr);
+ }
+
+ qCDebug(lcPopupWindow) << "forwarding" << pe << "to popup menu:" << targetWindow;
+ QQuickWindowPrivate::get(targetWindow)->deliveryAgent->event(pe);
+
+ // Restore the event before we return
+ QMutableEventPoint::setScenePosition(pe->point(0), scenePos);
+ if (grabber)
+ pe->setExclusiveGrabber(pe->point(0), grabber);
+ } else if (pe->isEndEvent()) {
+ // To support opening a Menu on press (e.g on a MenuBarItem), followed by
+ // a drag and release on a MenuItem inside the Menu, we ask the Menu to
+ // perform a click on the active MenuItem, if any.
+ if (targetPopupWindow)
+ QQuickPopupPrivate::get(targetPopupWindow->popup())->handleReleaseWithoutGrab(pe->point(0));
+ }
+}
+
+bool QQuickPopupWindow::event(QEvent *e)
+{
+ Q_D(QQuickPopupWindow);
+ d->forwardEventToParentMenuOrMenuBar(e);
+
+ return QQuickWindowQmlImpl::event(e);
+}
+
+void QQuickPopupWindow::windowChanged(QWindow *window)
+{
+ if (window) {
+ connect(window, &QWindow::xChanged, this, &QQuickPopupWindow::parentWindowXChanged);
+ connect(window, &QWindow::yChanged, this, &QQuickPopupWindow::parentWindowYChanged);
+ }
+}
+
+QPoint QQuickPopupWindow::global2Local(const QPoint &pos) const
+{
+ Q_D(const QQuickPopupWindow);
+ QQuickPopup *popup = d->m_popup;
+ Q_ASSERT(popup);
+ const QPoint scenePos = popup->window()->mapFromGlobal(pos);
+ // Popup's coordinates are relative to the nearest parent item.
+ return popup->parentItem() ? popup->parentItem()->mapFromScene(scenePos).toPoint() : scenePos;
+}
+
+void QQuickPopupWindow::parentWindowXChanged(int newX)
+{
+ const auto popupLocalPos = global2Local({x(), y()});
+ handlePopupPositionChangeFromWindowSystem({newX + popupLocalPos.x(), y()});
+}
+
+void QQuickPopupWindow::parentWindowYChanged(int newY)
+{
+ const auto popupLocalPos = global2Local({x(), y()});
+ handlePopupPositionChangeFromWindowSystem({x(), newY + popupLocalPos.y()});
+}
+
+void QQuickPopupWindow::handlePopupPositionChangeFromWindowSystem(const QPoint &pos)
+{
+ Q_D(QQuickPopupWindow);
+ QQuickPopup *popup = d->m_popup;
+ if (!popup)
+ return;
+ QQuickPopupPrivate *popupPrivate = QQuickPopupPrivate::get(popup);
+
+ const auto localPos = global2Local(pos);
+
+ const qreal oldX = popup->x();
+ const qreal oldY = popup->y();
+
+ qCDebug(lcPopupWindow) << "A window system event changed the popup's position to be " << localPos;
+
+ popupPrivate->x = popupPrivate->effectiveX = localPos.x();
+ popupPrivate->y = popupPrivate->effectiveY = localPos.y();
+
+ if (!qFuzzyCompare(oldX, localPos.x()))
+ emit popup->xChanged();
+ if (!qFuzzyCompare(oldY, localPos.y()))
+ emit popup->yChanged();
+}
+
+void QQuickPopupWindow::implicitWidthChanged()
+{
+ Q_D(const QQuickPopupWindow);
+ if (auto popup = d->m_popup)
+ setWidth(popup->implicitWidth());
+}
+
+void QQuickPopupWindow::implicitHeightChanged()
+{
+ Q_D(const QQuickPopupWindow);
+ if (auto popup = d->m_popup)
+ setHeight(popup->implicitHeight());
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/quicktemplates/qquickpopupwindow_p_p.h b/src/quicktemplates/qquickpopupwindow_p_p.h
new file mode 100644
index 0000000000..0b9842c059
--- /dev/null
+++ b/src/quicktemplates/qquickpopupwindow_p_p.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQUICKPOPUPWINDOW_P_P_H
+#define QQUICKPOPUPWINDOW_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qquickwindowmodule_p.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPopup;
+class QQuickPopupWindowPrivate;
+
+class Q_QUICKTEMPLATES2_EXPORT QQuickPopupWindow : public QQuickWindowQmlImpl
+{
+ Q_OBJECT
+ QML_ANONYMOUS
+
+public:
+ explicit QQuickPopupWindow(QQuickPopup *popup, QWindow *parent = nullptr);
+ ~QQuickPopupWindow();
+ QQuickPopup *popup() const;
+
+protected:
+ void hideEvent(QHideEvent *e) override;
+ void moveEvent(QMoveEvent *e) override;
+ void resizeEvent(QResizeEvent *e) override;
+ bool event(QEvent *e) override;
+
+private:
+ void windowChanged(QWindow *window);
+ QPoint global2Local(const QPoint& pos) const;
+ void parentWindowXChanged(int newX);
+ void parentWindowYChanged(int newY);
+ void handlePopupPositionChangeFromWindowSystem(const QPoint &pos);
+ void implicitWidthChanged();
+ void implicitHeightChanged();
+
+ Q_DISABLE_COPY(QQuickPopupWindow)
+ Q_DECLARE_PRIVATE(QQuickPopupWindow)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPOPUPWINDOW_P_P_H
diff --git a/src/quicktemplates/qquickselectionrectangle.cpp b/src/quicktemplates/qquickselectionrectangle.cpp
index 435b12819b..1bf04b7094 100644
--- a/src/quicktemplates/qquickselectionrectangle.cpp
+++ b/src/quicktemplates/qquickselectionrectangle.cpp
@@ -170,7 +170,7 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
else
m_selectable->setSelectionEndPos(m_scrollToPoint);
updateHandles();
- const QSizeF dist = m_selectable->scrollTowardsSelectionPoint(m_scrollToPoint, m_scrollSpeed);
+ const QSizeF dist = m_selectable->scrollTowardsPoint(m_scrollToPoint, m_scrollSpeed);
m_scrollToPoint.rx() += dist.width() > 0 ? m_scrollSpeed.width() : -m_scrollSpeed.width();
m_scrollToPoint.ry() += dist.height() > 0 ? m_scrollSpeed.height() : -m_scrollSpeed.height();
m_scrollSpeed = QSizeF(qAbs(dist.width() * 0.007), qAbs(dist.height() * 0.007));
@@ -310,7 +310,7 @@ void QQuickSelectionRectanglePrivate::scrollTowardsPos(const QPointF &pos)
if (m_scrollTimer.isActive())
return;
- const QSizeF dist = m_selectable->scrollTowardsSelectionPoint(m_scrollToPoint, m_scrollSpeed);
+ const QSizeF dist = m_selectable->scrollTowardsPoint(m_scrollToPoint, m_scrollSpeed);
if (!dist.isNull())
m_scrollTimer.start(1);
}
diff --git a/src/quicktemplates/qquickspinbox.cpp b/src/quicktemplates/qquickspinbox.cpp
index 2a68edac33..6c5d47b69d 100644
--- a/src/quicktemplates/qquickspinbox.cpp
+++ b/src/quicktemplates/qquickspinbox.cpp
@@ -2,19 +2,14 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qquickspinbox_p.h"
-#include "qquickcontrol_p_p.h"
-#include "qquickindicatorbutton_p.h"
-#include "qquickdeferredexecute_p_p.h"
-#include <QtGui/qguiapplication.h>
-#include <QtGui/qstylehints.h>
+#include <private/qquickcontrol_p_p.h>
+#include <private/qquickindicatorbutton_p.h>
+#include <private/qquicktextinput_p.h>
+
+#include <private/qqmlengine_p.h>
#include <QtQml/qqmlinfo.h>
-#if QT_CONFIG(qml_locale)
-#include <QtQml/private/qqmllocale_p.h>
-#endif
-#include <QtQml/private/qqmlengine_p.h>
-#include <QtQuick/private/qquicktextinput_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/quicktemplates/qquicksplitview.cpp b/src/quicktemplates/qquicksplitview.cpp
index daff2a5710..1d41016f94 100644
--- a/src/quicktemplates/qquicksplitview.cpp
+++ b/src/quicktemplates/qquicksplitview.cpp
@@ -329,11 +329,14 @@ void QQuickSplitViewPrivate::layoutResizeSplitItems(qreal &usedWidth, qreal &use
// The handle shouldn't cross other handles, so use the right edge of
// the first handle to the left as the left edge.
qreal leftEdge = 0;
- if (m_pressedHandleIndex - 1 >= 0) {
- const QQuickItem *leftHandle = m_handleItems.at(m_pressedHandleIndex - 1);
- leftEdge = horizontal
- ? leftHandle->x() + leftHandle->width()
- : leftHandle->y() + leftHandle->height();
+ for (int i = m_pressedHandleIndex - 1; i >= 0; --i) {
+ const QQuickItem *nextHandleToTheLeft = m_handleItems.at(i);
+ if (nextHandleToTheLeft->isVisible()) {
+ leftEdge = horizontal
+ ? nextHandleToTheLeft->x() + nextHandleToTheLeft->width()
+ : nextHandleToTheLeft->y() + nextHandleToTheLeft->height();
+ break;
+ }
}
// The mouse can be clicked anywhere in the handle, and if we don't account for
@@ -428,14 +431,15 @@ void QQuickSplitViewPrivate::layoutResizeSplitItems(qreal &usedWidth, qreal &use
m_layoutData.insert(item, layoutData);
- qCDebug(qlcQQuickSplitView).nospace() << " - " << index << ": resized split item " << item
- << " (effective"
- << " minW=" << sizeData.effectiveMinimumWidth
- << ", minH=" << sizeData.effectiveMinimumHeight
- << ", prfW=" << sizeData.effectivePreferredWidth
- << ", prfH=" << sizeData.effectivePreferredHeight
- << ", maxW=" << sizeData.effectiveMaximumWidth
- << ", maxH=" << sizeData.effectiveMaximumHeight << ")";
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << index << ": calculated the following size data for split item " << item
+ << ": eminW=" << sizeData.effectiveMinimumWidth
+ << ", eminH=" << sizeData.effectiveMinimumHeight
+ << ", eprfW=" << sizeData.effectivePreferredWidth
+ << ", eprfH=" << sizeData.effectivePreferredHeight
+ << ", emaxW=" << sizeData.effectiveMaximumWidth
+ << ", emaxH=" << sizeData.effectiveMaximumHeight
+ << ", w=" << layoutData.width
+ << ", h=" << layoutData.height << "";
// Keep track of how much space has been used so far.
if (horizontal)
@@ -536,6 +540,9 @@ void QQuickSplitViewPrivate::limitAndApplySizes(qreal usedWidth, qreal usedHeigh
const qreal maxSize = horizontal ? width : height;
const qreal usedSize = horizontal ? usedWidth : usedHeight;
if (usedSize > maxSize) {
+ qCDebug(qlcQQuickSplitView).nospace() << "usedSize " << usedSize << " is greater than maxSize "
+ << maxSize << "; reducing size of non-filled items from right to left / bottom to top";
+
// If items don't fit, reduce the size of non-filled items from
// right to left / bottom to top. At this point filled item is
// already at its minimum size or usedSize wouldn't be > maxSize.
@@ -569,6 +576,8 @@ void QQuickSplitViewPrivate::limitAndApplySizes(qreal usedWidth, qreal usedHeigh
}
}
+ qCDebug(qlcQQuickSplitView).nospace() << " applying new sizes to " << count << " items (excluding hidden items)";
+
// Apply the new sizes into items
for (int index = 0; index < count; ++index) {
QQuickItem *item = qobject_cast<QQuickItem*>(contentModel->object(index));
@@ -605,6 +614,10 @@ void QQuickSplitViewPrivate::limitAndApplySizes(qreal usedWidth, qreal usedHeigh
attached->setPreferredHeight(layoutData.height);
}
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << index << ": resized item " << item << " from "
+ << item->width() << "x" << item->height() << " to "
+ << layoutData.width << "x" << layoutData.height;
+
item->setWidth(layoutData.width);
item->setHeight(layoutData.height);
}
diff --git a/src/quicktemplates/qquicktooltip.cpp b/src/quicktemplates/qquicktooltip.cpp
index 2a78e4d344..0493cd5f4e 100644
--- a/src/quicktemplates/qquicktooltip.cpp
+++ b/src/quicktemplates/qquicktooltip.cpp
@@ -102,6 +102,8 @@ public:
void opened() override;
+ Qt::WindowFlags popupWindowType() const override;
+
QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::ToolTip); }
int delay = 0;
@@ -141,6 +143,11 @@ void QQuickToolTipPrivate::opened()
startTimeout();
}
+Qt::WindowFlags QQuickToolTipPrivate::popupWindowType() const
+{
+ return Qt::ToolTip;
+}
+
QQuickToolTip::QQuickToolTip(QQuickItem *parent)
: QQuickPopup(*(new QQuickToolTipPrivate), parent)
{
diff --git a/src/quicktestutils/quick/visualtestutils_p.h b/src/quicktestutils/quick/visualtestutils_p.h
index 48f8b2d8f9..9b1c9a2aeb 100644
--- a/src/quicktestutils/quick/visualtestutils_p.h
+++ b/src/quicktestutils/quick/visualtestutils_p.h
@@ -15,6 +15,8 @@
// We mean it.
//
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformintegration.h>
#include <QtQml/qqmlexpression.h>
#include <QtQuick/private/qquickitem_p.h>
@@ -226,6 +228,10 @@ namespace QQuickVisualTestUtils
#define QQUICK_VERIFY_POLISH(item) \
QTRY_COMPARE(QQuickItemPrivate::get(item)->polishScheduled, false)
+#define SKIP_IF_NO_WINDOW_ACTIVATION \
+if (!(QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))) \
+ QSKIP("Window activation is not supported on this platform");
+
QT_END_NAMESPACE
#endif // QQUICKVISUALTESTUTILS_P_H
diff --git a/src/quickvectorimage/generator/qquickitemgenerator.cpp b/src/quickvectorimage/generator/qquickitemgenerator.cpp
index 171cb6889f..3425ecc13b 100644
--- a/src/quickvectorimage/generator/qquickitemgenerator.cpp
+++ b/src/quickvectorimage/generator/qquickitemgenerator.cpp
@@ -75,7 +75,7 @@ void QQuickItemGenerator::generateImageNode(const ImageNodeInfo &info)
auto *imageItem = new QQuickImage;
auto *imagePriv = static_cast<QQuickImageBasePrivate*>(QQuickItemPrivate::get(imageItem));
- imagePriv->pix.setImage(info.image);
+ imagePriv->currentPix->setImage(info.image);
imageItem->setX(info.rect.x());
imageItem->setY(info.rect.y());
diff --git a/src/quickvectorimage/generator/qquicknodeinfo_p.h b/src/quickvectorimage/generator/qquicknodeinfo_p.h
index b7123f53e0..9af3d0b03c 100644
--- a/src/quickvectorimage/generator/qquicknodeinfo_p.h
+++ b/src/quickvectorimage/generator/qquicknodeinfo_p.h
@@ -42,6 +42,7 @@ struct ImageNodeInfo : NodeInfo
{
QImage image;
QRectF rect;
+ QString externalFileReference;
};
struct StrokeStyle
diff --git a/src/quickvectorimage/generator/qquickqmlgenerator.cpp b/src/quickvectorimage/generator/qquickqmlgenerator.cpp
index 7db7983e68..b8d0dbef54 100644
--- a/src/quickvectorimage/generator/qquickqmlgenerator.cpp
+++ b/src/quickvectorimage/generator/qquickqmlgenerator.cpp
@@ -12,6 +12,7 @@
#include <private/qquickimagebase_p_p.h>
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qdir.h>
QT_BEGIN_NAMESPACE
@@ -79,10 +80,16 @@ QQuickQmlGenerator::QQuickQmlGenerator(const QString fileName, QQuickVectorImage
QQuickQmlGenerator::~QQuickQmlGenerator()
{
if (!outputFileName.isEmpty()) {
- QFile outFile(outputFileName);
- outFile.open(QIODevice::WriteOnly);
- outFile.write(result);
- outFile.close();
+ QFileInfo fileInfo(outputFileName);
+ QDir dir(fileInfo.absolutePath());
+ if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) {
+ qCWarning(lcQuickVectorImage) << "Failed to create path" << dir.absolutePath();
+ } else {
+ QFile outFile(outputFileName);
+ outFile.open(QIODevice::WriteOnly);
+ outFile.write(result);
+ outFile.close();
+ }
}
if (lcQuickVectorImage().isDebugEnabled()) {
@@ -157,11 +164,38 @@ void QQuickQmlGenerator::generateImageNode(const ImageNodeInfo &info)
if (!isNodeVisible(info))
return;
- QString fn = info.image.hasAlphaChannel() ? QStringLiteral("svg_asset_%1.png").arg(info.image.cacheKey())
- : QStringLiteral("svg_asset_%1.jpg").arg(info.image.cacheKey());
- // For now we just create a copy of the image in the current directory
- info.image.save(fn);
- qCDebug(lcQuickVectorImage) << "Saving copy of IMAGE" << fn;
+ const QFileInfo outputFileInfo(outputFileName);
+ const QDir outputDir(outputFileInfo.absolutePath());
+
+ QString filePath;
+
+ if (!m_retainFilePaths || info.externalFileReference.isEmpty()) {
+ filePath = m_assetFileDirectory;
+ if (filePath.isEmpty())
+ filePath = outputDir.absolutePath();
+
+ if (!filePath.isEmpty() && !filePath.endsWith(u'/'))
+ filePath += u'/';
+
+ QDir fileDir(filePath);
+ if (!fileDir.exists()) {
+ if (!fileDir.mkpath(QStringLiteral(".")))
+ qCWarning(lcQuickVectorImage) << "Failed to create image resource directory:" << filePath;
+ }
+
+ filePath += QStringLiteral("%1%2.png").arg(m_assetFilePrefix.isEmpty()
+ ? QStringLiteral("svg_asset_")
+ : m_assetFilePrefix)
+ .arg(info.image.cacheKey());
+
+ if (!info.image.save(filePath))
+ qCWarning(lcQuickVectorImage) << "Unabled to save image resource" << filePath;
+ qCDebug(lcQuickVectorImage) << "Saving copy of IMAGE" << filePath;
+ } else {
+ filePath = info.externalFileReference;
+ }
+
+ const QFileInfo assetFileInfo(filePath);
// TODO: this requires proper asset management.
stream() << "Image {";
@@ -172,7 +206,7 @@ void QQuickQmlGenerator::generateImageNode(const ImageNodeInfo &info)
stream() << "y: " << info.rect.y();
stream() << "width: " << info.rect.width();
stream() << "height: " << info.rect.height();
- stream() << "source: \"" << fn <<"\"";
+ stream() << "source: \"" << outputDir.relativeFilePath(assetFileInfo.absoluteFilePath()) <<"\"";
m_indentLevel--;
diff --git a/src/quickvectorimage/generator/qquickqmlgenerator_p.h b/src/quickvectorimage/generator/qquickqmlgenerator_p.h
index 81fc4d386b..2bef58b054 100644
--- a/src/quickvectorimage/generator/qquickqmlgenerator_p.h
+++ b/src/quickvectorimage/generator/qquickqmlgenerator_p.h
@@ -35,6 +35,36 @@ public:
void setCommentString(const QString commentString);
QString commentString() const;
+ void setRetainFilePaths(bool retainFilePaths)
+ {
+ m_retainFilePaths = retainFilePaths;
+ }
+
+ bool retainFilePaths() const
+ {
+ return m_retainFilePaths;
+ }
+
+ void setAssetFileDirectory(const QString &assetFileDirectory)
+ {
+ m_assetFileDirectory = assetFileDirectory;
+ }
+
+ QString assetFileDirectory() const
+ {
+ return m_assetFileDirectory;
+ }
+
+ void setAssetFilePrefix(const QString &assetFilePrefix)
+ {
+ m_assetFilePrefix = assetFilePrefix;
+ }
+
+ QString assetFilePrefix() const
+ {
+ return m_assetFilePrefix;
+ }
+
protected:
void generateNodeBase(const NodeInfo &info) override;
bool generateDefsNode(const NodeInfo &info) override;
@@ -61,6 +91,9 @@ private:
bool m_inShapeItem = false;
QByteArray m_shapeTypeName;
QString m_commentString;
+ bool m_retainFilePaths = false;
+ QString m_assetFileDirectory;
+ QString m_assetFilePrefix;
};
QT_END_NAMESPACE
diff --git a/src/quickvectorimage/generator/qsvgvisitorimpl.cpp b/src/quickvectorimage/generator/qsvgvisitorimpl.cpp
index c8dff7f518..a3aafb65cd 100644
--- a/src/quickvectorimage/generator/qsvgvisitorimpl.cpp
+++ b/src/quickvectorimage/generator/qsvgvisitorimpl.cpp
@@ -232,6 +232,7 @@ void QSvgVisitorImpl::visitImageNode(const QSvgImage *node)
fillCommonNodeInfo(node, info);
info.image = node->image();
info.rect = node->rect();
+ info.externalFileReference = node->filename();
m_generator->generateImageNode(info);
@@ -360,8 +361,8 @@ QString QSvgVisitorImpl::colorCssDescription(QColor color)
QString cssDescription;
cssDescription += QStringLiteral("rgba(");
cssDescription += QString::number(color.red()) + QStringLiteral(",");
- cssDescription += QString::number(color.blue()) + QStringLiteral(",");
cssDescription += QString::number(color.green()) + QStringLiteral(",");
+ cssDescription += QString::number(color.blue()) + QStringLiteral(",");
cssDescription += QString::number(color.alphaF()) + QStringLiteral(")");
return cssDescription;
@@ -376,7 +377,9 @@ void QSvgVisitorImpl::visitTextNode(const QSvgText *node)
bool needsRichText = false;
bool preserveWhiteSpace = node->whitespaceMode() == QSvgText::Preserve;
const QGradient *mainGradient = styleResolver->currentFillGradient();
+#if QT_CONFIG(texthtmlparser)
bool needsPathNode = mainGradient != nullptr;
+#endif
for (const auto *tspan : node->tspans()) {
if (!tspan) {
text += QStringLiteral("<br>");
@@ -415,14 +418,18 @@ void QSvgVisitorImpl::visitTextNode(const QSvgText *node)
&& styleResolver->currentFillGradient() != mainGradient) {
const QGradient grad = styleResolver->applyOpacityToGradient(*styleResolver->currentFillGradient(), styleResolver->currentFillOpacity());
styleTagContent += gradientCssDescription(&grad) + u';';
+#if QT_CONFIG(texthtmlparser)
needsPathNode = true;
+#endif
}
QString strokeColor = colorCssDescription(styleResolver->currentStrokeColor());
if (!strokeColor.isEmpty()) {
styleTagContent += QStringLiteral("-qt-stroke-color:%1;").arg(strokeColor);
- styleTagContent += QStringLiteral("-qt-stroke-width:%1;").arg(styleResolver->currentStrokeWidth());
+ styleTagContent += QStringLiteral("-qt-stroke-width:%1px;").arg(styleResolver->currentStrokeWidth());
+#if QT_CONFIG(texthtmlparser)
needsPathNode = true;
+#endif
}
if (tspan->whitespaceMode() == QSvgText::Preserve && !preserveWhiteSpace)
@@ -502,7 +509,7 @@ void QSvgVisitorImpl::visitTextNode(const QSvgText *node)
if (font.pixelSize() <= 0 && font.pointSize() > 0)
font.setPixelSize(font.pointSize()); // Pixel size stored as point size by SVG parser
-#ifndef QT_NO_TEXTHTMLPARSER
+#if QT_CONFIG(texthtmlparser)
if (needsPathNode) {
QTextDocument document;
document.setHtml(text);
diff --git a/src/quickvectorimage/qquickvectorimage.cpp b/src/quickvectorimage/qquickvectorimage.cpp
index 813679b853..deda4dca7c 100644
--- a/src/quickvectorimage/qquickvectorimage.cpp
+++ b/src/quickvectorimage/qquickvectorimage.cpp
@@ -7,6 +7,8 @@
#include <QtQuickVectorImageGenerator/private/qquickvectorimageglobal_p.h>
#include <QtCore/qloggingcategory.h>
+#include <private/qquicktranslate_p.h>
+
QT_BEGIN_NAMESPACE
/*!
@@ -26,6 +28,9 @@ QT_BEGIN_NAMESPACE
It currently supports the \c SVG file format.
+ Qt supports multiple options for displaying SVG files. For an overview and comparison of the
+ different ones, see the documentation of the \l{svgtoqml} tool.
+
\section1 QML Types
*/
@@ -72,6 +77,9 @@ void QQuickVectorImagePrivate::loadSvg()
svgItem->setParentItem(q);
q->setImplicitWidth(svgItem->width());
q->setImplicitHeight(svgItem->height());
+
+ q->updateSvgItemScale();
+
q->update();
}
@@ -108,6 +116,10 @@ QQuickVectorImage::QQuickVectorImage(QQuickItem *parent)
: QQuickItem(*(new QQuickVectorImagePrivate), parent)
{
setFlag(QQuickItem::ItemHasContents, true);
+
+ QObject::connect(this, &QQuickItem::widthChanged, this, &QQuickVectorImage::updateSvgItemScale);
+ QObject::connect(this, &QQuickItem::heightChanged, this, &QQuickVectorImage::updateSvgItemScale);
+ QObject::connect(this, &QQuickVectorImage::fillModeChanged, this, &QQuickVectorImage::updateSvgItemScale);
}
/*!
@@ -129,4 +141,84 @@ void QQuickVectorImage::setSource(const QUrl &source)
d->setSource(source);
}
+void QQuickVectorImage::updateSvgItemScale()
+{
+ Q_D(QQuickVectorImage);
+
+ if (d->svgItem == nullptr
+ || qFuzzyIsNull(d->svgItem->width())
+ || qFuzzyIsNull(d->svgItem->height())) {
+ return;
+ }
+
+ auto xformProp = d->svgItem->transform();
+ QQuickScale *scaleTransform = nullptr;
+ if (xformProp.count(&xformProp) == 0) {
+ scaleTransform = new QQuickScale;
+ scaleTransform->setParent(d->svgItem);
+ xformProp.append(&xformProp, scaleTransform);
+ } else {
+ scaleTransform = qobject_cast<QQuickScale *>(xformProp.at(&xformProp, 0));
+ }
+
+ if (scaleTransform != nullptr) {
+ qreal xScale = width() / d->svgItem->width();
+ qreal yScale = height() / d->svgItem->height();
+
+ switch (d->fillMode) {
+ case QQuickVectorImage::NoResize:
+ xScale = yScale = 1.0;
+ break;
+ case QQuickVectorImage::PreserveAspectFit:
+ xScale = yScale = qMin(xScale, yScale);
+ break;
+ case QQuickVectorImage::PreserveAspectCrop:
+ xScale = yScale = qMax(xScale, yScale);
+ break;
+ case QQuickVectorImage::Stretch:
+ // Already correct
+ break;
+ };
+
+ scaleTransform->setXScale(xScale);
+ scaleTransform->setYScale(yScale);
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.VectorImage::VectorImage::fillMode
+
+ This property defines what happens if the width and height of the VectorImage differs from
+ the implicit size of its contents.
+
+ \value VectorImage.NoResize The contents are still rendered at the size provided by
+ the input.
+ \value VectorImage.Stretch The contents are scaled to match the width and height of
+ the \c{VectorImage}. (This is the default.)
+ \value VectorImage.PreserveAspectFit The contents are scaled to fit inside the bounds of the
+ \c VectorImage, while preserving aspect ratio. The
+ actual bounding rect of the contents will sometimes be
+ smaller than the \c VectorImage item.
+ \value VectorImage.PreserveAspectCrop The contents are scaled to fill the \c VectorImage item,
+ while preserving the aspect ratio. The actual bounds of
+ the contents will sometimes be larger than the
+ \c VectorImage item.
+*/
+
+QQuickVectorImage::FillMode QQuickVectorImage::fillMode() const
+{
+ Q_D(const QQuickVectorImage);
+ return d->fillMode;
+}
+
+void QQuickVectorImage::setFillMode(FillMode newFillMode)
+{
+ Q_D(QQuickVectorImage);
+ if (d->fillMode == newFillMode)
+ return;
+ d->fillMode = newFillMode;
+ emit fillModeChanged();
+}
+
QT_END_NAMESPACE
+
diff --git a/src/quickvectorimage/qquickvectorimage_p.h b/src/quickvectorimage/qquickvectorimage_p.h
index 68ccc561a1..2153acb29b 100644
--- a/src/quickvectorimage/qquickvectorimage_p.h
+++ b/src/quickvectorimage/qquickvectorimage_p.h
@@ -27,16 +27,32 @@ class Q_QUICKVECTORIMAGE_EXPORT QQuickVectorImage : public QQuickItem
Q_OBJECT
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged)
QML_NAMED_ELEMENT(VectorImage)
public:
+ enum FillMode {
+ NoResize,
+ PreserveAspectFit,
+ PreserveAspectCrop,
+ Stretch
+ };
+ Q_ENUM(FillMode)
+
QQuickVectorImage(QQuickItem *parent = nullptr);
QUrl source() const;
void setSource(const QUrl &source);
+ FillMode fillMode() const;
+ void setFillMode(FillMode newFillMode);
+
signals:
void sourceChanged();
+ void fillModeChanged();
+
+private slots:
+ void updateSvgItemScale();
private:
Q_DISABLE_COPY(QQuickVectorImage)
diff --git a/src/quickvectorimage/qquickvectorimage_p_p.h b/src/quickvectorimage/qquickvectorimage_p_p.h
index 689a5e9b69..032748b525 100644
--- a/src/quickvectorimage/qquickvectorimage_p_p.h
+++ b/src/quickvectorimage/qquickvectorimage_p_p.h
@@ -40,6 +40,7 @@ public:
QUrl sourceFile;
QQuickItem *svgItem = nullptr;
+ QQuickVectorImage::FillMode fillMode = QQuickVectorImage::Stretch;
};
QT_END_NAMESPACE
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 01f437fe30..fda7868c8e 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -200,6 +200,27 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
if (!engine.isNull() && !engine.data()->incubationController())
engine.data()->setIncubationController(offscreenWindow->incubationController());
+ q->setMouseTracking(true);
+ q->setFocusPolicy(Qt::StrongFocus);
+#ifndef Q_OS_MACOS
+ /*
+ Usually, a QTouchEvent comes from a touchscreen, and we want those
+ touch events in Qt Quick. But on macOS, there are no touchscreens, and
+ WA_AcceptTouchEvents has a different meaning: QApplication::notify()
+ calls the native-integration function registertouchwindow() to change
+ NSView::allowedTouchTypes to include NSTouchTypeMaskIndirect when the
+ trackpad cursor enters the window, and removes that mask when the
+ cursor exits. In other words, WA_AcceptTouchEvents enables getting
+ discrete touchpoints from the trackpad. We rather prefer to get mouse,
+ wheel and native gesture events from the trackpad (because those
+ provide more of a "native feel"). The only exception is for
+ MultiPointTouchArea, and it takes care of that for itself. So don't
+ automatically set WA_AcceptTouchEvents on macOS. The user can still do
+ it, but we don't recommend it.
+ */
+ q->setAttribute(Qt::WA_AcceptTouchEvents);
+#endif
+
#if QT_CONFIG(quick_draganddrop)
q->setAcceptDrops(true);
#endif
@@ -607,41 +628,22 @@ QImage QQuickWidgetPrivate::grabFramebuffer()
*/
/*!
- Constructs a QQuickWidget with the given \a parent.
- The default value of \a parent is 0.
+ Constructs a QQuickWidget with a default QML engine as a child of \a parent.
+ The default value of \a parent is \c nullptr.
*/
QQuickWidget::QQuickWidget(QWidget *parent)
: QWidget(*(new QQuickWidgetPrivate), parent, {})
{
- setMouseTracking(true);
- setFocusPolicy(Qt::StrongFocus);
-#ifndef Q_OS_MACOS
- /*
- Usually, a QTouchEvent comes from a touchscreen, and we want those
- touch events in Qt Quick. But on macOS, there are no touchscreens, and
- WA_AcceptTouchEvents has a different meaning: QApplication::notify()
- calls the native-integration function registertouchwindow() to change
- NSView::allowedTouchTypes to include NSTouchTypeMaskIndirect when the
- trackpad cursor enters the window, and removes that mask when the
- cursor exits. In other words, WA_AcceptTouchEvents enables getting
- discrete touchpoints from the trackpad. We rather prefer to get mouse,
- wheel and native gesture events from the trackpad (because those
- provide more of a "native feel"). The only exception is for
- MultiPointTouchArea, and it takes care of that for itself. So don't
- automatically set WA_AcceptTouchEvents on macOS. The user can still do
- it, but we don't recommend it.
- */
- setAttribute(Qt::WA_AcceptTouchEvents);
-#endif
d_func()->init();
}
/*!
- Constructs a QQuickWidget with the given QML \a source and \a parent.
- The default value of \a parent is 0.
+ Constructs a QQuickWidget with a default QML engine and the given QML \a source
+ as a child of \a parent.
-*/
+ The default value of \a parent is \c nullptr.
+ */
QQuickWidget::QQuickWidget(const QUrl &source, QWidget *parent)
: QQuickWidget(parent)
{
@@ -649,19 +651,15 @@ QQuickWidget::QQuickWidget(const QUrl &source, QWidget *parent)
}
/*!
- Constructs a QQuickWidget with the given QML \a engine and \a parent.
+ Constructs a QQuickWidget with the given QML \a engine as a child of \a parent.
- Note: In this case, the QQuickWidget does not own the given \a engine object;
+ \note The QQuickWidget does not take ownership of the given \a engine object;
it is the caller's responsibility to destroy the engine. If the \a engine is deleted
- before the view, status() will return QQuickWidget::Error.
-
- \sa Status, status(), errors()
+ before the view, \l status() will return \l QQuickWidget::Error.
*/
QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent)
: QWidget(*(new QQuickWidgetPrivate), parent, {})
{
- setMouseTracking(true);
- setFocusPolicy(Qt::StrongFocus);
d_func()->init(engine);
}
@@ -1315,12 +1313,6 @@ QPlatformBackingStoreRhiConfig QQuickWidgetPrivate::rhiConfig() const
QWidgetPrivate::TextureData QQuickWidgetPrivate::texture() const
{
- Q_Q(const QQuickWidget);
- if (!q->isWindow() && q->internalWinId()) {
- qWarning() << "QQuickWidget cannot be used as a native child widget."
- << "Consider setting Qt::AA_DontCreateNativeWidgetSiblings";
- return {};
- }
return { outputTexture, nullptr };
}
diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h
index b5eb7b4ba5..181fbd8d92 100644
--- a/src/quickwidgets/qquickwidget_p.h
+++ b/src/quickwidgets/qquickwidget_p.h
@@ -67,7 +67,7 @@ public:
QPlatformTextureList::Flags textureListFlags() override;
QImage grabFramebuffer() override;
- void init(QQmlEngine* e = 0);
+ void init(QQmlEngine* e = nullptr);
void ensureBackingScene();
void initOffscreenWindow();
void ensureEngine() const;